Layout¶
Use rows to put fields side by side, fieldsets to group them under a title, and
widths to size the columns. The layout is part of the form class, so
<?= $form ?> renders it and every page using the form looks the same.
Example¶
A delivery form with two sections, columns of different widths, and two sections side by side:
<?php
declare(strict_types=1);
namespace App\Forms;
use Ephraitech\Forms\Form;
class DeliveryForm extends Form
{
protected function define(): void
{
$this->hidden('order_id');
$this->fieldset('Contact', function (): void {
$this->row(function (): void {
$this->text('first_name', 'First name')->rules('required')->width(6);
$this->text('last_name', 'Last name')->rules('required')->width(6);
});
$this->tel('phone', 'Phone number')->rules('required');
});
$this->fieldset('Delivery address', function (): void {
$this->text('street', 'Street and building')->rules('required');
$this->row(function (): void {
$this->text('town', 'Town')->rules('required')->width(8);
$this->text('postcode', 'Postcode');
});
})->description('We deliver within Kampala and Entebbe.');
$this->row(function (): void {
$this->fieldset('Billing', function (): void {
$this->select('billing', 'Invoice to', ['me' => 'Me', 'company' => 'My company']);
})->width(6);
$this->fieldset('Timing', function (): void {
$this->date('deliver_on', 'Deliver on')->rules('required|valid_date[Y-m-d]');
})->width(6);
})->addClass('g-4');
$this->submit('Save delivery details');
}
}
The view stays a single line: <?= $form ?>.
How it works¶
- Rows
row()places the fields defined inside its closure next to each other. Each field takes the columns set withwidth(), out of 12. Fields without a width share whatever is left: in the address row, the town takes 8 columns and the postcode the remaining 4. On small screens the columns stack.- Fieldsets
fieldset('Title', ...)groups fields under a<legend>, which screen readers announce before each field inside it.description()adds a line under the title. Use''as the title for a group without one.- Nesting
- Rows and fieldsets can contain each other. Billing and Timing are
fieldsets placed side by side in a row, each with
width(6). - Classes
addClass()works on rows and fieldsets, such asg-4for wider gutters.- Hidden fields
- A hidden field never takes a column, wherever it is defined.
Layout only decides where fields appear. Validation, validated(), fill()
and field('town') work exactly as they do without it.
Arranging a form in the view¶
When a page needs a layout of its own, build it in the view from pieces:
<?= $form->open() ?>
<?= $form->errorSummary() ?>
<div class="row g-3">
<div class="col-md-4"><?= $form->field('first_name') ?></div>
<div class="col-md-4"><?= $form->field('last_name') ?></div>
<div class="col-md-4"><?= $form->field('phone') ?></div>
</div>
<?= $form->fields('street', 'town', 'postcode', 'billing', 'deliver_on') ?>
<div class="d-flex gap-2">
<?= $form->control('submit') ?>
<a href="<?= site_url('orders') ?>" class="btn btn-outline-secondary">Cancel</a>
</div>
<?= $form->field('order_id') ?>
<?= $form->close() ?>
| Method | Renders |
|---|---|
open() |
The <form> tag with the CSRF field, the hidden form name and, for PUT, PATCH and DELETE forms, the _method field |
errorSummary() |
A list of every error linking to its field, or nothing when there are none |
field('name') |
One field with its label, error and help text |
fields('a', 'b') |
Several fields in that order, without the form's layout |
control('name') |
Only the input, select or button, without label or wrapper |
close() |
</form> |
fields() with no names renders every field in the form's layout.
Common mistakes¶
Leaving out open(). Always start a custom layout with open(). Besides
the CSRF field, it adds a hidden field naming the form, which the package uses
to tell which form a submission or redirect belongs to.
Forgetting fields in a custom view. A field you do not render is not
submitted. Required fields then fail validation with an error the visitor
cannot see, unless you show errorSummary().
Widths outside rows. width() only has an effect inside a row.
Related¶
- Getting started uses a two-column layout
- Customising views changes the classes rows and sections use