Skip to main content

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'
]
]);
info

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'
]
]);
info

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();
}