Skip to main content
Advanced filter builder Advanced Filter Builder is a custom filtering system that gives your users a simple, yet powerful way to quickly build custom queries. Each filter inside the builder can be used multiple times and grouped into or groups, allowing your users to drill down and find the data they need. Advanced Filter Builder was designed to make filtering easy for your users with a simple UI and natural filtering language. For developers, Advanced Filter Builder couldn’t be easier to implement. Advanced Filter Builder can automatically generates text, numeric, date, boolean, and select filters from your table columns! You can also seamlessly integrate your existing filters or override the auto-generated ones allowing you to fully customize the filtering experience.
Important: Adding AdvancedTables to your table is required for Advanced Filter Builder to properly work.

Using Advanced Filter Builder

To enable the Advanced Filter Builder, add AdvancedFilterBuilder to your table’s ->filter() method:
return $table
    ->columns([
        ...
    ])
    ->filters([
        AdvancedFilter::make(),
    ])

Enabling Column Filters

Column Filters To automatically generate Column Filters for each of your table columns, you may use the ->includeColumns() method. This will automatically map your table’s compatible columns to the appropriate Column Filter and make them available in Advanced Filter Builder’s picker:
AdvancedFilter::make()
    ->includeColumns()
Tip: If you wish to only use some Column Filters, you may use either include or exclude columns.

Column Filter types

Advanced Filter Builder includes multiple different custom Column Filters, each with it’s own set of operators:

Text Filter

The TextFilter allows you to filter text strings with operators like is, is not, starts with, does not end with, contains, etc. Text Filter When appropriate, the TextFilter can also transform the is and is not operators into a multiple select dropdown: Text Filter with select

Numeric Filter

The NumericFilter allows you to filter numbers with operators like equal to, greater than, less than or equal to, between, positive, etc. Numeric filter

Date Filter

The DateFilter allows you to filter dates combining operators like yesterday, in the next, before, between, etc. with units like day, week, months ago, years from now, etc. Date filter

Select Filter

Advanced Table’s custom SelectFilter combines Filament’s SelectFilter with operators is, is not, is empty, is not empty. Select filter

Automatic column mapping

Advanced Filter Builder will automatically map your table columns to the appropriate filter depending on the type of column:
  1. TextColumn::make()->date() and TextColumn::make()->dateTime() columns will be mapped to the DateFilter.
  2. TextColumn::make()->numeric() and TextColumn::make()->money() columns will be mapped to the NumericFilter.
  3. Aggregate Relationship columns count, avg, min, max, and sum will be mapped to an aggregate NumericFilter.
  4. Any remaining TextColumn will be mapped to the TextFilter.
  5. SelectColumn will be mapped to Advanced Filter’s custom SelectFilter.
  6. CheckboxColumn, ToggleColumn, ImageColumn, IconColumn will be mapped to Filament’s Ternary Filter.

Customizing filters

Advanced Filter Builder uses the methods on your columns to automatically determine the appropriate filter to use. However, sometimes your table column may not match the type of filter you need. For example, if you are using a TextColumn to display an numeric amount, but aren’t using the ->numeric() method, Advanced Filter Builder wouldn’t know it’s best to use a NumericFilter. In these cases, it’s easy to customize the filter manually using the ->filters() method.

Customizing a Column Filter

You may manually define a Column Filter for a particular column by passing the desired filter type to the ->filters() method. The name of the filter should be the column you wish to override.
Tip: Any filter you add to the ->filters() array will be shown in the filters dropdown by default. To override this behavior you can use the ->defaultFilters() method to configure which filters, if any, are shown by default.
Note: When you are customizing a Column Filter the name of the filter must match the name of the column in your Filament table. If not, it will not appear in the Filter Picker.
AdvancedFilter::make()
    ->filters([
        NumericFilter::make('shipping_price') // Use the NumericFilter on the shipping_price column
    ])
To enable the Select field inside of the TextFilter, you may use a TextFilter and then pass in an array of options:
AdvancedFilter::make()
    ->filters([
        TextFilter::make('country')
            ->options(fn () => Country::all()->pluck('name', 'id')),
    ])
You may also pass in a relationship to automatically load the available options:
AdvancedFilter::make()
    ->filters([
        TextFilter::make('customer.name')
            ->relationship(name: 'customer', titleAttribute:'name')
            ->multiple()
            ->preload(),
    ])
Finally, if your table column only needs a dropdown of options to select from (ie, it doesn’t need additional operators like starts with, contains, etc.), you may manually map your column to Advanced Filter Builder’s custom SelectFilter:
use Archilex\AdvancedTables\Filters\SelectFilter;

AdvancedFilter::make()
    ->filters([
        SelectFilter::make('status')
            ->options([
                'processing' => 'Processing',
                'new' => 'New',
                'shipped' => 'Shipped',
                'delivered' => 'Delivered',
                'cancelled' => 'Cancelled',
            ])
            ->multiple(), 
    ])
Important: Be sure to import Archilex\AdvancedTables\Filters\SelectFilter to see the is, is not, is empty, and is not empty operators.

Customizing a column filter’s operators

You may customize a column filter’s operators using either the ->includeOperators() or ->excludeOperators() methods:
AdvancedFilter::make()
    ->filters([
        TextFilter::make('name')
            ->includeOperators([
                TextOperator::CONTAINS,
                TextOperator::DOES_NOT_CONTAIN
            ]), 
        SelectFilter::make('status')
            ->includeOperators([
                TextOperator::IS, // The SelectFilter uses the TextOperator
            ]), 
        DateFilter::make('created_at')
            ->excludeOperators([
                DateOperator::YESTERDAY,
                DateOperator::TODAY,
                DateOperator::TOMORROW
            ]), 
        NumericFilter::make('total_price')
            ->excludeOperators([
                NumericOperator::EQUAL_TO,
                NumericOperator::NOT_EQUAL_TO
            ]),
    ])
To customize a column filter’s operators globally, you can call the static configuringUsing() method from the boot() method of a service provider:
public function boot()
{
    TextFilter::configureUsing(function (TextFilter $filter) {
        return $filter->includeOperators([
            TextOperator::CONTAINS,
            TextOperator::DOES_NOT_CONTAIN
        ]);
    });
}
includeOperators() and excludeOperators() can also take a closure meaning you can further customize which operators are available:
TextFilter::configureUsing(function (TextFilter $filter) {
    return $filter->includeOperators(function (TextFilter $filter) {
        return $filter->getName() === 'currency'
            ? [TextOperator::CONTAINS, TextOperator::DOES_NOT_CONTAIN]
            : [TextOperator::IS, TextOperator::IS_NOT];
    });
});

Customizing a column filter’s default operator

To customize a column filter’s default operator you may pass the name of the operator to the ->defaultOperator() method:
AdvancedFilter::make()
    ->filters([
        TextFilter::make('name')
            ->defaultOperator(TextOperator::CONTAINS),
    ])
To customize a column filter’s default operator globally, you can call the static configuringUsing() method from the boot() method of a service provider:
public function boot()
{
    TextFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(TextOperator::CONTAINS));
    DateFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(DateOperator::TODAY));
    SelectFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(TextOperator::IS));
    NumericFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(NumericOperator::GREATER_THAN));
}
defaultOperator() can also take a closure meaning you can further customize which operator is the default:
TextFilter::configureUsing(function (TextFilter $filter) {
    return $filter->defaultOperator(function (TextFilter $filter) {
        return $filter->getName() === 'currency' 
            ? TextOperator::CONTAINS 
            : TextOperator::IS;
    }); 
});

Adding custom filters

Advanced Filter Builder can also seamlessly integrate any of Filament’s filters, including custom filters. This allows a filter to be used multiple times as well as in “or groups”.
Tip: Any filter you add to the ->filters() array will be shown in the filters dropdown by default. To override this behavior you can use the ->defaultFilters() method to configure which filters, if any, are shown by default.
To add a filter to Advanced Filter Builder, pass the filter into the ->filters() method:
AdvancedFilter::make()
    ->filters([
        Filter::make('is_active')
            ->query(fn (Builder $query): Builder => $query->where('is_active', true))
            ->toggle(),
    ])
Note: Any filter that has the same name as your table column, will be override the automatically mapped column filter. If the filter name does not match any of the table columns it will be added as an additional filter.
Important: If you are updating from a prior release and your users have already saved created User Views with filters, don’t worry, Advanced Filter Builder will automatically map them to the first filter group. However, if you are using Preset Views with default filters, you will need to adjust your filters to be compatible with Advanced Filter Builder.

Using filters alongside Advanced Filter Builder

You may still use any of Filament’s filters alongside Advanced Filter Builder by adding it as you normally would to your table’s ->filters() method:
return $table
    ->columns([
        ...
    ])
    ->filters([
        Filter::make('is_active')
            ->query(fn (Builder $query): Builder => $query->where('is_active', true))
            ->toggle(),
        AdvancedFilter::make(),
    ])
The above will add a single Is active toggle filter to the filter dropdown as well as display the Advanced Filter Builder below it.

Including columns

To only filter some of your columns, you may pass an array of column names you wish to include to the ->includeColumns() method:
AdvancedFilter::make()
    ->includeColumns([
        'is_active',
        'currency',
        'address.city',
    ]);
Important: If you are customizing a Column Filter, that column must be included in the ->includesColumns() method.

Excluding columns

You may instead exclude columns by passing an array of columns names to the ->excludeColumns() method:
AdvancedFilter::make()
    ->excludeColumns([
        'status',
        'customer.name',
        'created_at',
    ]);
Important: If you are customizing a Column Filter, that column must not be excluded from the ->excludesColumns() method.

Setting the default filters

By default, every filter included in Advanced Filter Builder’s ->filters() method will be shown in the table’s filter dropdown. Column Filters that haven’t been overriden in the ->filters() method will be available in the filter picker. To not display any column filters you can pass an empty array to the ->defaultFilters() method:
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->defaultFilters([])
To only display some filters by default, you may pass the name of your filter to the ->defaultFilters() method inside a double array. You may also use this method to define Column Filters you wish to be displayed by default in the filter dropdown:
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->defaultFilters([['status']])
Important: Be sure to add your filters inside a double array.
You can also set up multiple default groups:
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->defaultFilters([['status'], ['status']])

Disabling Or Groups

By default, Advanced Filter Builder allows your filters to be used in “or groups”. You may disable this feature by passing false to the ->orGroups() method:
AdvancedFilter::make()
    ->orGroups(false)

Layout options

Advanced Filter Builder responsively adapts to any of the available FilterLayouts (AboveContent, BelowContent, AboveContentCollapsible, Modal, SlideOver, Dropdown). When the builder is used with the Dropdown layout (Filament’s default layout), the user will also be presented with an “Expand View” button that will allow the dropdown to expand into a slideOver. If you using the Modal layout, it’s recommended you set the ->filtersFormWidth() on the table to at least 3xl so the form elements have space to flow:
use Archilex\AdvancedTables\Filters\AdvancedFilter;
use Filament\Tables\Actions\Action;
use Filament\Tables\Table;
use Filament\Tables\Enums\FiltersLayout;
 
public function table(Table $table): Table
{
    return $table
        ->filters([
            AdvancedFilter::make(),
        ])
        ->filtersLayout(FiltersLayout::Modal)
        ->filtersFormWidth('3xl')
}
When using Filament’s default Dropdown filter layout, the user will also be presented with an “Expand View” button that will allow the dropdown to expand into a slideOver. The expand view link in this view is absolute positioned (ugly…I know). If you are using translatable fields, this may cause the link to overlap. You may change the position of the expand view link by passing an array of styles to the ->filterBuilderExpandViewStyles() method:
AdvancedTablesPlugin::make()
    ->filterBuilderExpandViewStyles(['right: 100px', 'top: 24px'])
This method also take a closure allowing you to set different positions based on a condition such as locale:
use Illuminate\Support\Facades\App;

AdvancedTablesPlugin::make()
    ->filterBuilderExpandViewStyles(fn () => App::isLocale('es') ? ['right: 100px', 'top: 24px'] : ['right: 80px', 'top: 24px'])

Always opening the filter as a slideOver

If you would prefer Advanced Filter Builder to always open in a slideOver or modal, you may use Filament’s filtersTriggerAction() method:
use Archilex\AdvancedTables\Filters\AdvancedFilter;
use Filament\Tables\Actions\Action;
use Filament\Tables\Table;
 
public function table(Table $table): Table
{
    return $table
        ->filters([
            AdvancedFilter::make(),
        ])
        ->filtersFormWidth('md')
        ->filtersTriggerAction(
            fn (Action $action) => $action
                ->slideOver()
        );
}

Adding icons to the Filter Picker

You can add icons to the Filter Picker by passing an array of icons to the ->icons() method where the name of your filter is the key and the icon is the value:
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->icons([
        'status' => 'heroicon-o-clock',
        'currency' => 'heroicon-o-currency-euro',
        'customer' => 'heroicon-o-user',
        'created_at' => 'heroicon-o-calendar',
    ])

Enabling search in the Filter Picker

If the Filter Picker has a lot of available filters you can enable a search field using the ->filterPickerSearch() method:
AdvancedFilter::make()
    ->filterPickerSearch()

Configuring the number of Filter Picker columns

To change the number of columns the Filter Picker may occupy, you may use the ->filterPickerColumns() method:
AdvancedFilter::make()
    ->filterPickerColumns(2)
Passing an integer will determine how many columns are displayed at the lg breakpoint. You may also pass an array:
AdvancedFilter::make()
    ->filterPickerColumns(['sm' => 2])

Configuring the Filter Picker width

To customize the width of the Filter Picker, you may use the ->filterPickerWidth() method, and specify a width - xs, sm, md, lg, xl, 2xl, etc.
AdvancedFilter::make()
    ->filterPickerWidth('md')
Tip: Since the slideOver is confined to width md, it is recommended the Filter Picker not be set to a width larger than md as larger sizes will cause the slideOver to horizontally scroll.

Configuring the maximum height of the Filter Picker

To add a maximum height to the Filter Picker, which, in turn, allows the picker to be scrolled, you may use the ->filterPickerMaxHeight() method, passing a CSS length:
AdvancedFilter::make()
    ->filterPickerMaxHeight('240px')

Hiding the filter indicator group labels

When adding multiple filter groups (“or” groups), an the Filter Group number (ie “Filter Group 1”) will be prepended to the indicator to help differentiate between the different filter groups. You may disable this by passing false to the ->prependFilterGroupLabels() method:
 AdvancedFilter::make()
    ->prependFilterGroupLabels(false)
You may also hide the filter group label when there is only one filter group:
 AdvancedFilter::make()
    ->prependFilterGroupLabels(prependFilterGroupLabelWhenSoleGroup: false)
And of course, this can be set globally in your service provider:
AdvancedFilter::configureUsing(function (AdvancedFilter $filter) {
    return $filter->prependFilterGroupLabels(prependFilterGroupLabelWhenSoleGroup: false); 
}); 
Tip: The name/translation of the label can be modified in the language file.

Customizing the sequence of filter indicator group colors

When adding multiple filter groups (“or” groups), the indicators will be displayed in different colors to help differentiate between the different filter groups. By default, the indicators will be colored in the following sequence: primary, info, gray, success, danger, warning. You may choose a different sequence by passing an array of colors to the ->indicatorColors() method:
AdvancedFilter::make()
    ->indicatorColors(['info', 'success'])
Any default color that is not defined in the array will be appended after the last defined color.

Customizing the buttons and labels

You may customize Advanced Filter Builders buttons, labels, and filter operators in the language file.