Modals
Overview
Actions may require additional confirmation or input from the user before they run. You may open a modal before an action is executed to do this.
Confirmation modals
You may require confirmation before an action is run using the requiresConfirmation()
method. This is useful for particularly destructive actions, such as those that delete records.
use App\Models\Post;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
The confirmation modal is not available when a
url()
is set instead of anaction()
. Instead, you should redirect to the URL within theaction()
closure.
Modal forms
You may also render a form in the modal to collect extra information from the user before the action runs.
You may use components from the Form Builder to create custom action modal forms. The data from the form is available in the $data
array of the action()
closure:
use App\Models\Post;
use App\Models\User;
use Filament\Forms\Components\Select;
Action::make('updateAuthor')
->form([
Select::make('authorId')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->required(),
])
->action(function (array $data, Post $record): void {
$record->author()->associate($data['authorId']);
$record->save();
})
Filling the form with existing data
You may fill the form with existing data, using the fillForm()
method:
use App\Models\Post;
use App\Models\User;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
Action::make('updateAuthor')
->fillForm(fn (Post $record): array => [
'authorId' => $record->author->id,
])
->form([
Select::make('authorId')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->required(),
])
->action(function (array $data, Post $record): void {
$record->author()->associate($data['authorId']);
$record->save();
})
Using a wizard as a modal form
You may create a multistep form wizard inside a modal. Instead of using a form()
, define a steps()
array and pass your Step
objects:
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Wizard\Step;
Action::make('create')
->steps([
Step::make('Name')
->description('Give the category a unique name')
->schema([
TextInput::make('name')
->required()
->live()
->afterStateUpdated(fn ($state, callable $set) => $set('slug', Str::slug($state))),
TextInput::make('slug')
->disabled()
->required()
->unique(Category::class, 'slug'),
])
->columns(2),
Step::make('Description')
->description('Add some extra details')
->schema([
MarkdownEditor::make('description'),
]),
Step::make('Visibility')
->description('Control who can view it')
->schema([
Toggle::make('is_visible')
->label('Visible to customers.')
->default(true),
]),
])
Disabling all form fields
You may wish to disable all form fields in the modal, ensuring the user cannot edit them. You may do so using the disabledForm()
method:
use App\Models\Post;
use App\Models\User;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
Action::make('approvePost')
->form([
TextInput::make('title'),
Textarea::make('content'),
])
->fillForm(fn (Post $record): array => [
'title' => $record->title,
'content' => $record->content,
])
->disabledForm()
->action(function (Post $record): void {
$record->approve();
})
Customizing the modal's heading, description, and submit action label
You may customize the heading, description and label of the submit button in the modal:
use App\Models\Post;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->modalHeading('Delete post')
->modalDescription('Are you sure you\'d like to delete this post? This cannot be undone.')
->modalSubmitActionLabel('Yes, delete it')
Adding an icon inside the modal
You may add an icon inside the modal using the modalIcon()
method:
use App\Models\Post;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->modalIcon('heroicon-o-trash')
By default, the icon will inherit the color of the action button. You may customize the color of the icon using the modalIconColor()
method:
use App\Models\Post;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->color('danger')
->modalIcon('heroicon-o-trash')
->modalIconColor('warning')
Customizing the alignment of modal content
By default, modal content will be aligned to the start, or centered if the modal is xs
or sm
in width. If you wish to change the alignment of content in a modal, you can use the modalAlignment()
method and pass it Alignment::Start
or Alignment::Center
:
use Filament\Support\Enums\Alignment;
Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->modalAlignment(Alignment::Center)
Custom modal content
You may define custom content to be rendered inside your modal, which you can specify by passing a Blade view into the modalContent()
method:
use App\Models\Post;
Action::make('advance')
->action(fn (Post $record) => $record->advance())
->modalContent(view('filament.pages.actions.advance'))
Passing data to the custom modal content
You can pass data to the view by returning it from a function. For example, if the $record
of an action is set, you can pass that through to the view:
use Illuminate\Contracts\View\View;
Action::make('advance')
->action(fn (Contract $record) => $record->advance())
->modalContent(fn (Contract $record): View => view(
'filament.pages.actions.advance',
['record' => $record],
))
Adding custom modal content below the form
By default, the custom content is displayed above the modal form if there is one, but you can add content below using modalContentFooter()
if you wish:
use App\Models\Post;
Action::make('advance')
->action(fn (Post $record) => $record->advance())
->modalContentFooter(view('filament.pages.actions.advance'))
Adding an action to custom modal content
You can add an action button to your custom modal content, which is useful if you want to add a button that performs an action other than the main action. You can do this by registering an action with the registerModalActions()
method, and then passing it to the view:
use App\Models\Post;
use Illuminate\Contracts\View\View;
Action::make('advance')
->registerModalActions([
Action::make('report')
->requiresConfirmation()
->action(fn (Post $record) => $record->report()),
])
->action(fn (Post $record) => $record->advance())
->modalContent(fn (Action $action): View => view(
'filament.pages.actions.advance',
['action' => $action],
))
Now, in the view file, you can render the action button by calling getModalAction()
:
<div>
{{ $action->getModalAction('report') }}
</div>
Using a slide-over instead of a modal
You can open a "slide-over" dialog instead of a modal by using the slideOver()
method:
Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->slideOver()
Instead of opening in the center of the screen, the modal content will now slide in from the right and consume the entire height of the browser.