Filament: Add Form On Top Above The Table

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.

avatar

cool!

avatar

Thank you so much sir ..

avatar

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!

avatar

Hard to tell without debuging. Maybe there's a bug or maybe you are missing something.

avatar

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.

avatar

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>

👍 1

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 80 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials