In this 3-in-1 lesson, let's talk about the most common operations we can do with Filament columns/fields:
- Validating fields
- Sort columns in the table
- Search by table column
I decided to group those into one lesson because they are so easily accomplished in Filament that the lesson will be pretty short, anyway.
Validating Fields in Filament
If you want to add behavior to form fields, you can chain multiple methods to the XxxxxInput::make()
method.
One of the most widely used ones would be ->required()
for the validation.
return $form ->schema([ Forms\Components\TextInput::make('name')->required(), Forms\Components\TextInput::make('price')->required(), ]);
Just by adding this, we have this behavior in the create/edit forms: validation error and asterisk sign near the label.
And there are more Filament methods for validation that you can chain together.
Forms\Components\TextInput::make('name') ->required() ->unique(),
Notice: I start putting those methods on separate lines for better readability.
Some Filament validation methods have extra parameters for convenience. The example above shows the unique()
method, and by default the Edit form will not ignore the current record, so it would show a validation error even if you haven't changed anything in the form.
To avoid that, you can add a parameter:
Forms\Components\TextInput::make('name') ->required() ->unique(ignoreRecord: true),
But those Filament validation methods are just convenient helpers on top of all Laravel validation rules, so in most cases, you would use the Laravel ones. Just add ->rule()
or ->rules()
and use any of the familiar Laravel rules:
Forms\Components\TextInput::make('price') ->required() ->rule('numeric'),
And that's all you need to know about validation: just use the same typical Laravel rules, with an optional Filament "syntax sugar" helper on top.
Sort Table Columns
If we continue the logic of chaining various methods to ::make()
in Filament, the same applies to the table columns.
To add sorting behavior to any table column, just add ->sortable()
at the end.
return $table ->columns([ Tables\Columns\TextColumn::make('name')->sortable(), Tables\Columns\TextColumn::make('price')->sortable(), ])
This is how the table looks now:
You can click any column and sort the table by column values ascending/descending. Those would be auto-added as parameters in the URL:
You can also specify how the table should be sorted by default. This is done by adding a method defaultSort()
, but this time we add it to the $table
object, not the columns.
return $table ->columns([ // ... ]) ->defaultSort('price', 'desc') ->filters([ // ... ]) // ... other methods
Search By Table Column
Remember how we added sortable()
for a column to be sortable? So yeah, in the same fashion, you can just add ->searchable()
.
return $table ->columns([ Tables\Columns\TextColumn::make('name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('price') ->sortable(), ])
Then Filament adds a search bar on the top-right where you can search for values in any columns you specified as searchable.
And the search filtering happens automatically in "live" mode. You don't have to hit Enter or any other button.
Notice. The way Filament fields/columns are configured with method chaining gives a convenient experience of IDE autocomplete when typing. Extremely useful if you're not sure what exactly the method is called.
Now, what if you want the search to be visible at the top of the table column instead of the top-right corner "global" search? The searchable()
method has two parameters, to set what "mode" of search to enable.
By default, the parameter values are these:
->searchable(isIndividual: false, isGlobal: true)
But let's switch them around and see what happens:
Tables\Columns\TextColumn::make('name') ->sortable() ->searchable(isIndividual: true, isGlobal: false),
And now, we see the search input at the top of the column, and we don't see the global search field anymore.
That's it for this lesson. These are just a few examples of how Filament allows you to customize the fields by just adding the chain of methods to the ::make()
. You will see that pattern more and more throughout this course as we add more methods for more complex behavior.
Super powerful and so simple. Thanks for this.
Thanks for the nice work! Is it possible to provide a custom search query for the field with a closure? Looking at the definition of the searchable method, I'd think it's possible, but I can't seem to find any examples of this.
You can add closure there:
https://filamentphp.com/docs/3.x/tables/columns/getting-started#searching
This is what I was looking for, and it works. Thanks!
What can I do for methods that require a relationship instance? For example my model contains this method:
public function highestBid() { return $this->offers()->orderBy('bid_amount', 'desc')->first(); }
it can only be accessed like $model->highestBid()->bid_amount. While I could do some query builder I have other relationships across the app that require it to be used with parentheses. I cannot figure out how to list it in a Filament Table, it appears to return null. I've tried:
Tables\Columns\TextColumn::make('highest_bid') ->label('Highest Bid') ->relationship(name: 'highestBid', titleAttribute: 'bid_amount')
Tables\Columns\TextColumn::make('highest_bid') ->label('Highest Bid') ->formatStateUsing(function ($record) { return $record->highestBid()->bid_amount ?? 'N/A'; }),
In addition to this issue, I also cannot figure out how to eager load 3 levels deep for this specific column. Tables\Columns\TextColumn::make('item.product.name') ->label('Product'),
Any chance I can get a brainiac to assist? Thanks
To get a relationship - the name has to match exactly. In your case
highest_bid
should behighestBid
and that would work.Loading 3 levels is something different, but in theory - it should work the same. If it doesn't, you can use a custom column or
formatStateUsing()
on the column and do what you need to do there :)Interesting. Thanks for the speedy reply! Once I get my coffee Ima give this a hoot.
Tracked my errors back to /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:586
My highestBid function is is not a standard Eloquent relationship but rather a custom method that returns a specific value. Creating this into a proper attribuite works. So I made new method for now since the original method has ties to jobs/etc.
public function getHighestBidfilamentAttribute() { return $this->offers()->orderBy('bid_amount', 'desc')->first()->bid_amount; }
Figure I share incase there is anyone else suffering from the occasional brainfart like me.
Also incredible response time, wasn't really exepecting one, given I don't post here ever. Incredible team, LaravelDaily to the MOON! Many thanks
Thank you for the nice words! We try to reply as soon as possible as that is part of the membership people get! (we are even faster on discord :) ). The only time we can be slow - is the weekend :)
By what you wrote - it makes sense. You do need to have a relationship for most filament things to function properly. So if you were able to make it work with a relationship - that's awesome!
Hello, excellent course.
I have a problem though, Filament shows me a blank page when I click on the column title to sort it. I followed this tutorial and the official filament example (about a system for vets) and same problem.
When I go to http://daily.test/admin/products I can see the table, then when I click on the colum "name" for example, the url changes to http://daily.test/admin/products?tableSortColumn=name&tableSortDirection=asc but the page is black (I'm using dark mode), and the cursor mouse is like cursor-pointer in the whole page.
Then if I copy and paste this url http://daily.test/admin/products?tableSortColumn=name&tableSortDirection=asc in the browser and press enter everything is ok, but if I cllick on the column name I got the same error.
I'm using a new Laravel 11 project and I installed Filament using composer require filament/filament:"^3.2.57-stable" -W
I googled a lot but no luck.
Any suggestion about this problem?
Thanks so much
I would start to debug this by:
composer update
to get latest versions of all packagesphp artisan cache:clear
to clear up cached views (sometimes it doesn't trigger automatically)But other than that - this is a really specific issue, which can be either a simple code mistake or an issue in the code. Hard to debug without the actual code and in a comment :)
Thanks for the response.
After many attempts and googling, I found the solution here https://github.com/filamentphp/filament/issues/13360
If you are using the latest Laravel version (06/01/2025) and you can't install filament using the command from the official website (composer require filament/filament:"^3.2" -W) use
composer require filament/filament -W
Thanks so much.