We recently received a question on our YouTube channel, so in this tutorial, we will answer it.
In this tutorial, we will see how we can add a form above a table list in a resource.
In this example, we have a Contact
Laravel Model with a ContactResource
Filament Resource with three required fields: first name, last name, and email.
Above the table, we can have widgets. Widgets are Livewire Component. Because of that, we can add the Filament Form to a Livewire Component. So first, let's create a widget and register it in the Resource.
php artisan make:filament-widget CreateContactWidget --resource=ContactResource
This command created a widget class app/Filament/Resources/ContactResource/Widgets/CreateContactWidget.php
, and a view resources/views/filament/resources/contact-resource/widgets/create-contact-widget.blade.php
.
app/Filament/Resources/ContactResource.php:
class ContactResource extends Resource{ // ... public static function getWidgets(): array { return [ ContactResource\Widgets\CreateContactWidget::class, ]; }}
Next, we must add widget to a list page in the getHeaderWidgets
method to show it above the table.
The
getFooterWidgets
method will show widget below the table.
app/Filament/Resources/ContactResource/ListContacts.php:
class ListContacts extends ListRecords{ protected static string $resource = ContactResource::class; protected function getHeaderActions(): array { return [ Actions\CreateAction::make(), ]; } protected function getHeaderWidgets(): array { return [ ContactResource\Widgets\CreateContactWidget::class, ]; } }
Now we can add a form to the CreateContactWidget
widget.
app/Filament/Resources/ContactResource/Widgets/CreateContactWidget.php:
use Filament\Forms\Form;use Filament\Widgets\Widget;use Filament\Forms\Contracts\HasForms;use Filament\Forms\Components\TextInput;use Filament\Forms\Concerns\InteractsWithForms; class CreateContactWidget extends Widget implements HasForms{ use InteractsWithForms; protected static string $view = 'filament.resources.contact-resource.widgets.create-contact-widget'; protected int | string | array $columnSpan = 'full'; public ?array $data = []; public function mount(): void { $this->form->fill(); } public function form(Form $form): Form { return $form ->schema([ TextInput::make('first_name') ->required(), TextInput::make('last_name') ->required(), TextInput::make('email') ->email() ->required(), ]) ->statePath('data'); }}
To show the form in the view file, we must add the {{ $this->form }}
inside the form.
resources/views/filament/resources/contact-resource/widgets/create-contact-widget.blade.php:
<x-filament-widgets::widget> <x-filament::section> <form wire:submit="create"> {{ $this->form }} <x-filament::button type="submit" class="mt-3"> {{ __('filament-panels::resources/pages/create-record.form.actions.create.label') }} </x-filament::button> </form> </x-filament::section></x-filament-widgets::widget>
We can see the form above the table.
Now, we can save the form and refresh the table to see new records without manually refreshing the page. In the forms wire:submit
directive we provided, the create
method will be called when clicking the create button.
app/Filament/Resources/ContactResource/Widgets/CreateContactWidget.php:
use App\Models\Contact; class CreateContactWidget extends Widget implements HasForms{ // ... public function create(): void { Contact::create($this->form->getState()); $this->form->fill(); $this->dispatch('contact-created'); }}
In the create
method, we create a record, initialize a new form, and dispatch a Livewire event. Now, we must listen for this event on the list page and refresh the table.
app/Filament/Resources/ContactResource/ListContacts.php:
use Livewire\Attributes\On; class ListContacts extends ListRecords{ protected static string $resource = ContactResource::class; #[On('contact-created')] public function refresh() {} // ...}
And that's it. We have a form above the table in the filament resource.
The full source code is available in this GitHub repository.
If you want more Filament examples, you can find more real-life projects on our FilamentExamples.com.
cool!
Thank you so much sir ..
What a great tutorial, thank you!
Question for you... How would you handle the createOptionForm from a Select component?
I have it specified, yet when I click the + icon to bring up its own modal, nothing happens and there is nothing in the console that tells me anything useful.
Thanks!
Hard to tell without debuging. Maybe there's a bug or maybe you are missing something.
Definitely a strong possibility :)
I will continue to see if I can get this to work as everything else does.
I am not just not sure if the createOptionForm works with Formbuilder when the form is in a custom Livewire component. I'm not getting any console errors currently.
Just a quick tip. To show spinner inside the button after submiting the form, add
form="create"
to the button.<x-filament::button type="submit" form="create" class="mt-3" wire:loading.attr="disabled"> {{ __('filament-panels::resources/pages/create-record.form.actions.create.label') }} </x-filament::button>