Field Layout
When a form has a lot of fields, you may want to position all the inputs in your form.
Below are a list of field layouts you may use.
Columns
You can achieve this by defining a fieldLayout
:
public function fieldLayout(bool $forDetail, ?Model $model = null): ?FieldLayout
{
return (new FieldLayout)
->column('name', 'email')
}
A column can accept any amount of fields. In the example above, name and email will be shown next to each other.
If you want fields on below each other:
public function fieldLayout(bool $forDetail, ?Model $model = null): ?FieldLayout
{
return (new FieldLayout)
->column('name')
->column('email')
}
For more configurations, see: Column configuration
Tabs
You can also have columns within tabs:
return (new FieldLayout)
->tabs([
__('User') => [
'name',
'email',
],
__('Password') => [
'reset_method',
'checked_password'
],
]);
Steps
You can also use steps instead of tabs:
return (new FieldLayout)
->steps([
__('User') => [
'name',
'email',
],
__('Password') => [
'reset_method',
'checked_password'
],
]);
Disabling steps
You can disable and enable steps via the FormState
:
Text::make(__('Name'), 'name')
->onUpdate(function(ManagesForm $form, $name) {
if ($name === 'some name') {
$form->enableSteps(__('Authorization'), __('Password'));
return;
}
$form->disableSteps(__('Authorization'), __('Password'));
})
Vertical
if you want to have your steps to be aligned vertically, you need to add true as second argument:
return (new FieldLayout)
->steps([
__('User') => [
'name',
'email',
],
__('Password') => [
'reset_method',
'checked_password'
],
], true);
Always show submit button
You can also enable to always show the submit button (on every step) as the third argument:
return (new FieldLayout)
->steps([
__('User') => [
'name',
'email',
],
__('Password') => [
'reset_method',
'checked_password'
],
], false, true);
Cards
You can use cards to group your fields:
public function fieldLayout(bool $forDetail, ?Model $model = null): ?FieldLayout
{
return (new FieldLayout())
->cards([
__('Personlijke info') => [
'id',
'serial_number',
'gender',
['first_name', 'last_name' ],
'birth_date',
],
__('Bestanden') => [
'photo',
'contract',
'verzekeringen'
]
]);
}
By default, cards have a width of 6/12 (half of the viewport) and no set height. You can define a width and a height per card:
->cards([
__('Personlijke info') => [
'id',
'serial_number',
'gender',
['first_name', 'last_name' ],
'birth_date',
],
__('Bestanden') => [
'photo',
'contract',
'verzekeringen'
],
], [
__('Personlijke info') => [
'width' => 10,
'height' => 'lg'
],
__('Bestanden') => [
'width' => 'xs',
'height' => 'lg'
]
]);
Toggling
Cards have a toggling feature. The toggled state can be set by default from the backend.
->cards([
__('Personlijke info') => [
...
],
__('Bestanden') => [
...
],
], [
__('Personlijke info') => [
'width' => 10,
'height' => 'lg',
'toggled' => true // this is default to false
],
__('Bestanden') => [
'width' => 'xs',
'height' => 'lg'
]
]);
If the user overwrites the local state in his browser, the default won't be used anymore.
Cards can have the toggable feature disabled by passing toggable => false
to the card.
->cards([
__('Personlijke info') => [
...
],
__('Bestanden') => [
...
],
], [
__('Personlijke info') => [
'width' => 10,
'height' => 'lg',
'toggable' => false // true by default
],
__('Bestanden') => [
'width' => 'xs',
'height' => 'lg'
]
]);
If the card is not toggable, the toggled => false
option is ignored and the card will always be expanded.
To permanently disable the toggling feature you can configure on the frontend .env
DISABLE_TOGGLING=true
Tabs inside cards
You can also have multiple cards with tabs inside them:
return (new FieldLayout())
->cards([
__('invoicing::invoicing.Addressee') => [
['receiver', 'address_reference'],
'address',
'vat_number'
],
__('invoicing::invoicing.Settings') => [
__('invoicing::invoicing.Invoice details') => [
['status', 'predicted_number'],
['invoice_date', 'payment_due_days'],
['send_method', 'receiver_mail_to'],
['receiver_mail_cc', 'receiver_mail_bcc'],
],
__('invoicing::invoicing.Additional') => [
['invoiceTemplate', 'currency_code']
]
],
__('invoicing::invoicing.Invoice lines') => [
'invoiceLines'
],
__('invoicing::invoicing.Text above') => [
'text_above'
],
__('invoicing::invoicing.Text below') => [
'text_below'
],
], [
__('invoicing::invoicing.Addressee') => [
'width' => 'md'
],
__('invoicing::invoicing.Settings') => [
'width' => 'md'
],
__('invoicing::invoicing.Invoice lines') => [
'width' => 'xl'
],
__('invoicing::invoicing.Text Above') => [
'width' => 'md'
],
__('invoicing::invoicing.Text below') => [
'width' => 'md'
],
]);
Columns with cards
The field layout columns with cards can be used to put cards with fields in a column-based layout.
Regular column layout
The tabbed column layout puts different column layouts in tabs.
Implementing the regular column layout
(new FieldLayout)->cardColumns($fields, $columns)
$fields: array
This array should contain cards. Where the key is the card title and the value an array of field names.
$columns: array
This should be an two-dimensional array. $columns
should contain arrays that define each column that should be shown.
Each array should contain the width of a column and an array containing all the card titles that should be shown.
The max width a column can have is 12.
Providing 'width' => 6
will create a card with 50% view width.
public function fieldLayout(bool $forDetail, ?Model $model = null): ?FieldLayout
{
$fields = [
__('crm::crm.Organization') => [
'name',
'addresses'
],
__('crm::crm.Company information') => [
[
'kvk',
'vat_number',
]
],
__('crm::crm.Communication') => [
'emailAddresses',
'phoneNumbers',
],
];
return (new FieldLayout())
->cardColumns(
$fields,
[
[
'width' => '7',
'cards' => [
__('crm::crm.Organization'),
__('crm::crm.Company information'),
]
],
[
'width' => '5',
'cards' => [
__('crm::crm.Communication'),
]
],
]
);
}
Tabbed column layout
The regular column layout puts all the cards in a column layout.
Implementing the tabbed column layout
(new FieldLayout)->cardColumns($fields, $columns, $tabs)
$columns: array
The $columns
parameter as defined in the regular implementation should wrapped by an associative array where the key is the tab title.
$tabs: array
This should be an array containing the tab titles that should be shown.
private function detailColumnLayout(): CustomFieldLayout
{
$fields = [
__('crm::crm.Organization') => [
'name',
'type',
],
__('crm::crm.Addresses') => [
'addresses'
],
__('crm::crm.Additional') => [
'kvk',
'vat_number',
],
__('Extra') => [
'updated_at',
'created_at',
],
];
return (new FieldLayout())->cardColumns(
$fields,
[
__('Information') =>
[
[
'width' => '6',
'cards' => [
__('crm::crm.Organization'),
],
],
[
'width' => '6',
'cards' => [
__('crm::crm.Addresses'),
],
],
],
__('crm::crm.Additional') =>
[
[
'width' => 6,
'cards' => [
__('crm::crm.Additional'),
],
],
[
'width' => 6,
'cards' => [
__('Extra'),
]
]
],
],
[
__('Information'),
__('crm::crm.Additional')
]
);
}
Toggling
This layout has a toggling feature. The toggled state of a card can be set.
In the following example the 'Organization' card is collapsed by default and the 'Company information' card can't be collapsed by the user:
return (new FieldLayout())
->cardColumns(
$fields,
[
[
'width' => '7',
'cards' => [
__('crm::crm.Organization') => [
'toggled' => true,
],
__('crm::crm.Company information') => [
'toggable' => false
],
...
Column configuration
When you have multiple fields shown as columns in a row, the default class col
will be applied on every field.
Furthermore, each field will also have a min-width
of 150px
. You can however override this:
return (new FieldLayout())
->cards([
__('invoicing::invoicing.Settings') => [
__('invoicing::invoicing.Invoice details') => [
['status', 'predicted_number'],
['invoice_date', 'payment_due_days'],
// ['send_method', 'receiver_mail_to'],
// Apply your own class and min-width:
(new FieldLayoutColumn(['send_method', 'receiver_mail_to']))
->setColumnClass('')
->setColumnMinWidth(0),
['receiver_mail_cc', 'receiver_mail_bcc'],
],
Visibility
By default, your fieldLayout will be used on forms, but also on the detail page.
Like the fields, you may disable it while creating, viewing or editing:
return (new FieldLayout)->(...)->onlyOnCreate();
You can also customise 2 different layouts, one for Viewing and one for Creating with the bool $forDetail
param:
public function fieldLayout(bool $forDetail, ?Model $model = null): ?FieldLayout
{
if ($forDetail) {
return (new FieldLayout())
->cards([
'Details' => [
[ 'first_name', 'last_name' ]
],
'Description' => [
'description'
]
]);
}
return (new FieldLayout())
->steps([
'Details' => [
'first_name',
'last_name'
],
'Description' => [
'description'
]
])->onlyOnCreate();
}