Actions with a form
form() opens a modal dialog before the action runs. The fields work like
in forms: validation rules are derived from the fields
(required(), maxLength(), …) and invalid input is shown in the dialog
(422). The handler gets the converted values.
Action::make('addRole') ->label('Add role')->icon('plus-circle') ->permission('people.lifecycle') ->form(static fn (Form $form): Form => $form->schema([ BelongsTo::make('business_role_id')->label('Role')->relationship(BusinessRoleModel::class, 'name')->required(), DateInput::make('valid_from')->required()->default(date('Y-m-d')), DateInput::make('valid_until'), Textarea::make('reason')->maxLength(500), ])) ->handle(function ($person, array $data): string { // $data['business_role_id'] is the id of a role the user may see. service('roles')->grant($person, $data);
return 'Role added.'; }),Fields in dialogs
Section titled “Fields in dialogs”All fields work, including searchable BelongsTo, UserSelect
and lookup repeaters (their
searches are actions of the same component with the permission of the
action). Layouts such as sections or grids work too; keep dialogs short.
- Defaults (
default()) fill the dialog; the operation iscreate. FileUploadis not supported in dialogs.- The values are converted like in forms: numbers normalised,
BelongsToto ids, repeaters to JSON. - Virtual fields are passed in
$dataas well.
The form per record
Section titled “The form per record”On the detail page the form closure receives the record, so the dialog can depend on it – e.g. options with the current grants of a person, or the items the person already has:
->form(fn (Form $form, array|object $person): Form => $form->schema([ CheckboxList::make('ok')->options($this->assignedItems($person)),]))The form in rows and cards
Section titled “The form in rows and cards”In rows and cards, one dialog per action serves all rows of the list: its form is built once without a record (the closure receives an empty array) and the clicked row sets the record when the dialog opens. Forms of row actions must therefore not depend on the record. If building the form without a record fails, the action is not offered in rows; it stays available on the detail page.
Confirmation
Section titled “Confirmation”With confirm() the question is asked when the dialog is submitted.
Without a form, confirm() asks before the request is sent.