Skip to content

Custom filters

A filter supplies the input; a clause performs the comparison. Customize either independently.

This text filter accepts either admin or engineer and applies an Eloquent comparison:

use Illuminate\Database\Eloquent\Builder;
use InertiaX\Components\Table\Enums\DataSourceKind;
use InertiaX\Components\Table\Filters\Clauses\Clause;
use InertiaX\Components\Table\Filters\TextFilter;
TextFilter::make('role')
->clearClauses()
->addClause(
Clause::make('acme/role-equals', 'Has role')
->validateUsing(
fn (mixed $value): bool => in_array($value, ['admin', 'engineer'], true),
)
->applyUsing(
fn (Builder $query, string $column, string $value): Builder =>
$query->where($column, $value),
DataSourceKind::Eloquent,
),
);

This callback supports Eloquent only. See Clause API for value normalization and source contracts.

Add ->type('acme/role-filter') to the filter above, then register the input in React:

import type { TableFilterInputRendererProps, TableCustomizationOptions } from '@inertiax/react';
import { InertiaX } from '@inertiax/react-inertia';
function RoleInput({ ariaLabel, id, value, onChange }: TableFilterInputRendererProps) {
return (
<select
aria-label={ariaLabel}
id={id}
value={typeof value === 'string' ? value : ''}
onChange={(event) => onChange(event.target.value || undefined)}
>
<option value="">Any role</option>
<option value="admin">Administrator</option>
<option value="engineer">Engineer</option>
</select>
);
}
const usersTable = {
filterInputs: [
{ operation: 'register', key: 'acme/role-filter', value: RoleInput },
],
} satisfies TableCustomizationOptions;
export function UsersIndex() {
return <InertiaX prop="users" table={usersTable} />;
}

Emit undefined to clear a condition. Preserve the server’s value types: string "1", number 1, and Boolean true are distinct. A custom multi-select input must emit an array. The input also receives the filter definition and selected clause.

Use applyClauseUsing() to apply a filter’s comparisons to a different source field:

TextFilter::make('display_name', 'Name')
->applyClauseUsing(
function (Builder $query, mixed $value, \Closure $applyClause): Builder {
return $applyClause($query, 'full_name', $value);
},
DataSourceKind::Eloquent,
);

The source must have a full_name field. The selected clause still validates the input and performs the comparison. See Filter API for callback context.