Filters

Getting started

Filters allow you to scope the Eloquent query as a way to reduce the number of records in a table.

If you're using the filters in a Livewire component, you can put them in the getTableFilters() method:

protected function getTableFilters(): array
{
return [
// ...
];
}

If you're using them in admin panel resources or relation managers, you must put them in the $table->filters() method:

public static function table(Table $table): Table
{
return $table
->filters([
// ...
]);
}

Filters may be created using the static make() method, passing its name. The name of the filter should be unique. You should then pass a callback to query() which applies your filter's scope:

use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
 
Filter::make('is_featured')
->query(fn (Builder $query): Builder => $query->where('is_featured', true))

Setting a label

By default, the label of the filter, which is displayed in the filter form, 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')

Optionally, you can have the label automatically translated by using the translateLabel() method:

use Filament\Tables\Filters\Filter;
 
Filter::make('is_featured')->translateLabel() // Equivalent to `label(__('Is featured'))`

Using a toggle button instead of a checkbox

By default, filters use a checkbox to control the filter. Instead, you may switch to using a toggle button, using the toggle() method:

use Filament\Tables\Filters\Filter;
 
Filter::make('is_featured')->toggle()

Default filters

You may set a filter to be enabled by default, using the default() method:

use Filament\Tables\Filters\Filter;
 
Filter::make('is_featured')->label('Featured')->default()

Filter forms

By default, filters have two states: enabled and disabled. When the filter is enabled, it is applied to the query. When it is disabled it is not. This is controlled through a checkbox. However, some filters may require extra data input to narrow down the results further. You may use a custom filter form to collect this data.

Select filters

Select filters allow you to quickly create a filter that allows the user to select an option to apply the filter to their table. For example, a status filter may present the user with a few status options to pick from and filter the table using:

use Filament\Tables\Filters\SelectFilter;
 
SelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])

Select filters do not require a custom query() method. The column name used to scope the query is the name of the filter. To customize this, you may use the attribute() method:

use Filament\Tables\Filters\SelectFilter;
 
SelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->attribute('status_id')

Relationship select filters

Select filters are also able to automatically populate themselves based on a BelongsTo relationship. For example, if your table has a author relationship with a name column, you may use relationship() to filter the records belonging to an author:

use Filament\Tables\Filters\SelectFilter;
 
SelectFilter::make('author')->relationship('author', 'name')

You may customise the database query that retrieves options using the third parameter of the relationship() method:

use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;
 
SelectFilter::make('author')
->relationship('author', 'name', fn (Builder $query) => $query->withTrashed())

Multi-select filters

Multi-select filters allow you to quickly create a filter that allows the user to select multiple options to apply the filter to their table. For example, a status filter may present the user with a few status options to pick from and filter the table using:

use Filament\Tables\Filters\MultiSelectFilter;
 
MultiSelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])

Multi-select filters do not require a custom query() method. The column name used to scope the query is the name of the filter. To customize this, you may use the attribute() method:

use Filament\Tables\Filters\MultiSelectFilter;
 
MultiSelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->attribute('status_id')

Relationship multi-select filters

Multi-select filters are also able to automatically populate themselves based on a BelongsTo relationship. For example, if your table has a author relationship with a name column, you may use relationship() to filter the records belonging to a selection of authors:

use Filament\Tables\Filters\MultiSelectFilter;
 
MultiSelectFilter::make('author')->relationship('author', 'name')

Ternary filters

Ternary filters allow you to quickly create a filter which has three states - usually true, false and blank. To filter a column named is_admin to be true or false, you may use the ternary filter:

use Filament\Tables\Filters\TernaryFilter;
 
TernaryFilter::make('is_admin')

Another common pattern is to use a nullable column. For example, when filtering verified and unverified users using the email_verified_at column, unverified users have a null timestamp in this column. To apply that logic, you may use the nullable() method:

use Filament\Tables\Filters\TernaryFilter;
 
TernaryFilter::make('email_verified_at')
->nullable()

The column name used to scope the query is the name of the filter. To customize this, you may use the attribute() method:

use Filament\Tables\Filters\TernaryFilter;
 
TernaryFilter::make('verified')
->nullable()
->attribute('status_id')

You may customise the query used for each state of the ternary filter, using the queries() method:

use Illuminate\Database\Eloquent\Builder;
use Filament\Tables\Filters\TernaryFilter;
 
TernaryFilter::make('trashed')
->placeholder('Without trashed records')
->trueLabel('With trashed records')
->falseLabel('Only trashed records')
->queries(
true: fn (Builder $query) => $query->withTrashed(),
false: fn (Builder $query) => $query->onlyTrashed(),
blank: fn (Builder $query) => $query->withoutTrashed(),
)

Custom filter forms

You may use components from the Form Builder to create custom filter forms. The data from the custom filter form is available in the $data array of the query() callback:

use Filament\Forms;
use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
 
Filter::make('created_at')
->form([
Forms\Components\DatePicker::make('created_from'),
Forms\Components\DatePicker::make('created_until'),
])
->query(function (Builder $query, array $data): Builder {
return $query
->when(
$data['created_from'],
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '>=', $date),
)
->when(
$data['created_until'],
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '<=', $date),
);
})

Setting default values

If you wish to set a default filter value, you may use the default() method on the form component:

use Filament\Forms;
use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
 
Filter::make('created_at')
->form([
Forms\Components\DatePicker::make('created_from'),
Forms\Components\DatePicker::make('created_until')->default(now()),
])

Active indicators

When a filter is active, an indicator is displayed above the table content to signal that the table query has been scoped.

By default, the label of the filter is used as the indicator. You can override this:

use Filament\Tables\Filters\TernaryFilter;
 
TernaryFilter::make('is_admin')
->label('Administrators only?')
->indicator('Administrators')

Custom indicators

Not all indicators are simple, so you may need to use indicateUsing() to customize which indicators should be shown at any time.

For example, if you have a custom date filter, you may create a custom indicator that formats the selected date:

use Filament\Forms\Components\DatePicker;
use Filament\Tables\Filters\Filter;
 
Filter::make('created_at')
->form([DatePicker::make('date')])
// ...
->indicateUsing(function (array $data): ?string {
if (! $data['date']) {
return null;
}
 
return 'Created at ' . Carbon::parse($data['date'])->toFormattedDateString();
})

You may even render multiple indicators at once, by returning an array. If you have different fields associated with different indicators, you should use the field's name as the array key, to ensure that the correct field is reset when the filter is removed:

use Filament\Forms\Components\DatePicker;
use Filament\Tables\Filters\Filter;
 
Filter::make('created_at')
->form([
DatePicker::make('from'),
DatePicker::make('until'),
])
// ...
->indicateUsing(function (array $data): array {
$indicators = [];
 
if ($data['from'] ?? null) {
$indicators['from'] = 'Created from ' . Carbon::parse($data['from'])->toFormattedDateString();
}
 
if ($data['until'] ?? null) {
$indicators['until'] = 'Created until ' . Carbon::parse($data['until'])->toFormattedDateString();
}
 
return $indicators;
})

Appearance

By default, filters are displayed in a thin popover on the right side of the table, in 1 column.

To change the number of columns that filters may occupy, you may use the getTableFiltersFormColumns() method:

protected function getTableFiltersFormColumns(): int
{
return 3;
}

Adding more columns to the filter form will automatically widen the popover. To customize the popover width, you may use the getTableFiltersFormWidth() method, and specify a width from xs to 7xl:

protected function getTableFiltersFormWidth(): string
{
return '4xl';
}

Displaying filters above or below the table content

To render the filters above the table content instead of in a popover, you may use:

use Filament\Tables\Filters\Layout;
 
protected function getTableFiltersLayout(): ?string
{
return Layout::AboveContent;
}

To render the filters below the table content instead of in a popover, you may use:

use Filament\Tables\Filters\Layout;
 
protected function getTableFiltersLayout(): ?string
{
return Layout::BelowContent;
}

Persist filters in session

To persist the table filters in the user's session, use the shouldPersistTableFiltersInSession() method:

protected function shouldPersistTableFiltersInSession(): bool
{
return true;
}
Edit on GitHub

Still need help? Join our Discord community or open a GitHub discussion

Enjoying Filament?

We are open source at heart. To allow us to build new features, fix bugs, and run the community, we require your financial support.

Sponsor Filament on GitHub