# Filtering

> Add field filters, empty-value comparisons and pinned selects, and offer advanced filter groups.

Source: https://docs.inertiax.dev/table/guide/filters/

Call `filterable()` to make a column available in the **Filter** picker:

**Laravel**

```php
use InertiaX\Table\Columns\TextColumn;

TextColumn::make('name')->filterable();
```

Automatic filters are enabled by default. With `autoFilters()` enabled, InertiaX creates a filter for each filterable column and chooses its comparisons from the column type. When the column of an Eloquent model can be `null` in the database, its filter also offers **Is not empty** and **Is empty**. These filters populate the picker; value inputs appear only while adding or editing a condition.

## Declare a filter

Use the table’s `filters()` method for explicit filters and labels:

**Laravel**

```php
use InertiaX\Table\Filters\DateFilter;
use InertiaX\Table\Filters\SelectFilter;
use InertiaX\Table\Filters\TextFilter;

protected function filters(): array
{
    return [
        TextFilter::make('name')->defaultClause('contains'),
        SelectFilter::make('status')->options([
            'active' => 'Active',
            'invited' => 'Invited',
        ]),
        DateFilter::make('signed_up', 'Signed up')->column('created_at'),
    ];
}
```

A filter is a field users pick. Its key names it in links and filter state, and its clauses are the comparisons it offers. It queries the source field with the same name, unless `column()` names another one; the column stays on the server. Because the key and the column are separate, two filters can query one column:

**Laravel**

```php
TextFilter::make('email'),
TextFilter::make('email_domain', 'Email domain')
    ->column('email')
    ->setClauses(['ends-with']),
```

You can also call `addFilter()` on an inline table, or attach a filter to a column with `filter()`. An attached filter queries that column, including a `relationship()` column, and keeps the key you give it, or takes the column’s key. An explicit filter replaces the automatic filter with the same key, and a column with an attached filter gets no automatic one. Use `autoFilters(false)` to keep only explicit and attached filters.

## Filter empty values

**Laravel**

```php
use InertiaX\Table\Filters\DateTimeFilter;

DateTimeFilter::make('email_verified_at', 'Verified')->nullable();
```

`nullable()` adds **Is not empty** and **Is empty** after the filter’s other comparisons. They take no value. No comparison takes `null` as its value, so these two are how users find missing values.

## Keep a select filter in the toolbar

**Laravel**

```php
SelectFilter::make('status')
    ->options(['draft' => 'Draft', 'paid' => 'Paid'])
    ->pinned(),
SelectFilter::make('region')
    ->options(['eu' => 'Europe', 'us' => 'United States']),
```

`pinned()` keeps the `status` filter in the toolbar as a select. In Basic mode, choosing an option applies its Equals condition immediately; **Clear Status** removes only that condition. Other filters remain available through **Filter** and the applied chips.

A `multiple()` select, another comparison, repeated conditions, or Advanced mode show **Edit filters** instead. A page can replace the filters marked in PHP with its own `pinnedFilters` list:

**React**

```tsx
<AppTable prop="orders" customization={{ pinnedFilters: ['status', 'region'] }} />
```

This page also pins `region`; `[]` pins none. See [Pinned filters](https://docs.inertiax.dev/table/reference/react/#pinned-filters) for supported values and toolbar ownership.

## Select options

**Laravel**

```php
SelectFilter::make('role')->options([
    'admin' => 'Administrator',
    'engineer' => 'Engineer',
])->multiple();
```

`multiple()` lets the filter’s default **Equals** and **Not Equals** take several options. Use `autoOptions(limit: 200)` to discover the distinct values of the filter’s column. If there are more options than the limit, the UI shows a notice. Increase the limit or supply explicit options when users need the full set.

## Choose comparisons

A clause is a comparison such as “contains” or “equals”. Change the offered comparisons or the initial choice:

**Laravel**

```php
TextFilter::make('name')
    ->removeClause('not-contains')
    ->defaultClause('contains');
```

See [Filter API](https://docs.inertiax.dev/table/reference/filter/) for each filter’s clause set and [Custom filters](https://docs.inertiax.dev/table/guide/custom-filters/) for your own comparisons, inputs, or filters.

## Apply and edit filters

Basic mode is the default. Choose **Filter**, find a field, select a comparison and enter a value. **Add filter** closes the editor and leaves a chip showing the condition. Click the chip to edit it, then choose **Save**. Use its remove button to delete the condition.

Basic combines conditions with **and**. You can add the same field more than once, such as “Score greater than 50” and “Score less than 90”. Comparisons such as **Is empty** need no value.

Closing or cancelling the editor discards unsaved changes. **Clear filters** removes all applied conditions without clearing search. Applied changes reset the page and use the [search/filter request delay](https://docs.inertiax.dev/table/guide/request-lifecycle/#request-timing).

## Advanced filter groups

**Laravel**

```php
use InertiaX\Table\Enums\FilterMode;

UsersTable::make('users')->data($users)->filterMode(FilterMode::Advanced);
```

Advanced mode adds **or** and nested groups. Open **Filter** to build an expression, choosing the field, comparison and value for each condition. Choose **Apply filters** to save the expression and close the builder. The closed **Filters** control shows the number of applied conditions; click it to edit them.

Closing without applying discards changes. **Clear filters** clears the applied expression immediately. The fluent method also accepts `'basic'` or `'advanced'`.

## Dynamic options and callbacks

**Laravel**

```php
SelectFilter::make('status')->options(
    fn (): array => ['pending' => 'Pending', 'paid' => 'Paid'],
    'eloquent',
);
```

Declare the supported source kind when using an options closure. Request only the arguments you need from the [callback context table](https://docs.inertiax.dev/table/reference/callbacks/). Options resolve for each table execution; custom sources have no local dataset to inspect.

For shareable filter links, see [URL state](https://docs.inertiax.dev/table/guide/url-state/#filter-links).
