filament/tables
Powerful table builder for Filament admin panels. Add searchable, sortable, filterable tables with actions, bulk actions, and column types. Integrates cleanly with Eloquent and supports pagination, customization, and responsive layouts.
import Aside from "@components/Aside.astro" import AutoScreenshot from "@components/AutoScreenshot.astro" import UtilityInjection from "@components/UtilityInjection.astro"
Filters allow you to define certain constraints on your data, and allow users to scope it to find the information they need. You put them in the $table->filters() method.
Filters may be created using the static make() method, passing its unique name. You should then pass a callback to query() which applies your filter's scope:
use Filament\Tables\Filters\Filter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
public function table(Table $table): Table
{
return $table
->filters([
Filter::make('is_featured')
->query(fn (Builder $query): Builder => $query->where('is_featured', true))
// ...
]);
}
By default, using the Filter::make() method will render a checkbox form component. When the checkbox is on, the query() will be activated.
By default, the label of the filter is generated from the name of the filter. You may customize this using the label() method:
use Filament\Tables\Filters\Filter;
Filter::make('is_featured')
->label('Featured')
<UtilityInjection set="tableFilters" version="5.x">As well as allowing a static value, the label() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
Customizing the label in this way is useful if you wish to use a translation string for localization:
use Filament\Tables\Filters\Filter;
Filter::make('is_featured')
->label(__('filters.is_featured'))
By default, creating a filter with the Filter class will render a checkbox form component. When the checkbox is checked, the query() function will be applied to the table's query, scoping the records in the table. When the checkbox is unchecked, the query() function will be removed from the table's query.
Filters are built entirely on Filament's form fields. They can render any combination of form fields, which users can then interact with to filter the table.
The simplest example of managing the form field that is used for a filter is to replace the checkbox with a toggle button, using the toggle() method:
use Filament\Tables\Filters\Filter;
Filter::make('is_featured')
->toggle()
Whether you are using a checkbox, a toggle or a select, you can customize the built-in form field used for the filter, using the modifyFormFieldUsing() method. The method accepts a function with a $field parameter that gives you access to the form field object to customize:
use Filament\Forms\Components\Checkbox;
use Filament\Tables\Filters\Filter;
Filter::make('is_featured')
->modifyFormFieldUsing(fn (Checkbox $field) => $field->inline(false))
<UtilityInjection set="tableFilters" version="5.x" extras="Field;;Filament\Forms\Components\Field;;$field;;The field object to modify.">The function passed to modifyFormFieldUsing() can inject various utilities as parameters.</UtilityInjection>
You may set a filter to be enabled by default, using the default() method:
use Filament\Tables\Filters\Filter;
Filter::make('is_featured')
->default()
If you're using a select filter, visit the "applying select filters by default" section.
To persist the table filters in the user's session, use the persistFiltersInSession() method:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->persistFiltersInSession();
}
By default, filter changes are deferred and do not affect the table, until the user clicks an "Apply" button. To disable this and make the filters "live" instead, use the deferFilters(false) method:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->deferFilters(false);
}
When deferring filters, you can customize the "Apply" button, using the filtersApplyAction() method, passing a closure that returns an action. All methods that are available to customize action trigger buttons can be used:
use Filament\Actions\Action;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->filtersApplyAction(
fn (Action $action) => $action
->link()
->label('Save filters to table'),
);
}
By default, all records will be deselected when the filters change. Using the deselectAllRecordsWhenFiltered(false) method, you can disable this behavior:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->deselectAllRecordsWhenFiltered(false);
}
By default, modifications to the Eloquent query performed in the query() method will be applied inside a scoped where() clause. This is to ensure that the query does not clash with any other filters that may be applied, especially those that use orWhere().
However, the downside of this is that the query() method cannot be used to modify the query in other ways, such as removing global scopes, since the base query needs to be modified directly, not the scoped query.
To modify the base query directly, you may use the baseQuery() method, passing a closure that receives the base query:
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Tables\Filters\TernaryFilter;
TernaryFilter::make('trashed')
// ...
->baseQuery(fn (Builder $query) => $query->withoutGlobalScopes([
SoftDeletingScope::class,
]))
When a user interacts with a table record (e.g., clicking an action button), Filament resolves that record from the database. By default, all active filter conditions are applied, ensuring users cannot access records outside their filter scope.
However, some filters like TrashedFilter modify global scopes rather than restricting access. When a record's state changes after the user saw it in the table, you may still want the user to interact with it.
You may mark a filter to be excluded when resolving records using the excludeWhenResolvingRecord() method:
use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
Filter::make('trashed')
->query(fn (Builder $query) => $query->onlyTrashed())
->baseQuery(fn (Builder $query) => $query->withoutGlobalScopes([
SoftDeletingScope::class,
]))
->excludeWhenResolvingRecord()
When excludeWhenResolvingRecord() is used:
query() callback is not applied when resolving recordsbaseQuery() callback is still applied when resolving recordsTo customize the filters trigger buttons, you may use the filtersTriggerAction() method, passing a closure that returns an action. All methods that are available to customize action trigger buttons can be used:
use Filament\Actions\Action;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->filtersTriggerAction(
fn (Action $action) => $action
->button()
->label('Filter'),
);
}
The vast majority of methods used to configure filters accept functions as parameters instead of hardcoded values:
use App\Models\Author;
use Filament\Tables\Filters\SelectFilter;
SelectFilter::make('author')
->options(fn (): array => Author::query()->pluck('name', 'id')->all())
This alone unlocks many customization possibilities.
The package is also able to inject many utilities to use inside these functions, as parameters. All customization methods that accept functions as arguments can inject utilities.
These injected utilities require specific parameter names to be used. Otherwise, Filament doesn't know what to inject.
If you wish to access the current filter instance, define a $filter parameter:
use Filament\Tables\Filters\BaseFilter;
function (BaseFilter $filter) {
// ...
}
If you wish to access the current Livewire component instance that the table belongs to, define a $livewire parameter:
use Filament\Tables\Contracts\HasTable;
function (HasTable $livewire) {
// ...
}
If you wish to access the current table configuration instance that the filter belongs to, define a $table parameter:
use Filament\Tables\Table;
function (Table $table) {
// ...
}
The parameters are injected dynamically using reflection, so you are able to combine multiple parameters in any order:
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
function (HasTable $livewire, Table $table) {
// ...
}
You may inject anything from Laravel's container like normal, alongside utilities:
use Filament\Tables\Table;
use Illuminate\Http\Request;
function (Request $request, Table $table) {
// ...
}
How can I help you explore Laravel packages today?