abather/table-filters

table filters

Maintainers

Package info

github.com/Abather/table-filters

Homepage

pkg:composer/abather/table-filters

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-master 2026-04-06 18:55 UTC

This package is auto-updated.

Last update: 2026-04-06 18:58:58 UTC


README

Table Filters Banner

Latest Version on Packagist Total Downloads

Table Filters

A fluent builder for Filament table filters. Reduces repetitive filter boilerplate into a single chainable call.

Requirements

  • PHP 8.2+
  • Filament 4.x or 5.x

Installation

composer require abather/table-filters

Usage

Fluent builder (chained)

Use TableFilters::make(ResourceClass::class) inside your Filament resource's table() method and spread the result into filters().

use Abather\TableFilters\Tables\Filters\TableFilters;

public static function table(Table $table): Table
{
    return $table
        ->filters(
            TableFilters::make(static::class)
                ->date()
                ->numeric('price')
                ->select('status')
                ->toggle('is_active')
                ->relation('category', 'name')
                ->filters(),
        );
}

Standalone (individual filters)

Each filter is also available as a static method that returns a plain Filament Filter (or SelectFilter) component — the same object you would get from Filter::make() directly. This means you can chain any method from the Filament filter documentation on top of it, such as ->label(), ->hidden(), ->columnSpan(), ->default(), and so on.

use Abather\TableFilters\Tables\Filters\TableFilters;

public static function table(Table $table): Table
{
    return $table
        ->filters([
            // returned as-is
            TableFilters::dateFilter('created_at', 'Created'),

            // chain any Filament filter method on top
            TableFilters::numericFilter('price', 'Price')
                ->columnSpan(2)
                ->hidden(fn () => ! auth()->user()->can('filter-prices')),

            TableFilters::selectFilter(static::class, 'status', 'Status')
                ->label('Order Status')
                ->default('active'),

            TableFilters::toggleFilter('is_active', 'Active'),
            TableFilters::relationFilter('category', 'name'),
            TableFilters::relationDateFilter('orders', 'created_at', 'Order Date'),
            TableFilters::relationNumericFilter('orders', 'total', 'Order Total'),
        ]);
}

Note: selectFilter() requires the resource class as its first argument because it fetches distinct values from the database automatically.

Available Filters

date() / dateFilter()

Adds a date range filter (or a single date picker).

// chained
->date(
    field: 'created_at',   // column to filter on (default: 'created_at')
    label: null,           // optional label
    range: true,           // true → from/to pickers, false → single picker
    with_time: false,      // use DateTimePicker instead of DatePicker
)

// standalone
TableFilters::dateFilter(field: 'created_at', label: null, range: true, with_time: false)

numeric() / numericFilter()

Adds a numeric range filter (or an exact-value filter).

// chained
->numeric(
    field: 'price',
    label: null,
    range: true,   // true → from/to inputs, false → single input
)

// standalone
TableFilters::numericFilter(field: 'price', label: null, range: true)

select() / selectFilter()

Adds a select/dropdown filter. When no options are provided, distinct values are pulled from the database automatically.

// chained
->select(
    field: 'status',
    label: null,
    options: null,   // array, enum class-string, or null (auto-detect from DB)
    multiple: false,
    limit: 10,       // max distinct values fetched when options is null
)

// standalone — resource class is required as the first argument
TableFilters::selectFilter(resource: static::class, field: 'status', label: null, options: null, multiple: false, limit: 10)

toggle() / toggleFilter()

Adds a boolean toggle filter.

// chained
->toggle(
    field: 'is_active',
    label: null,
    default: false,   // whether the toggle is on by default
    negation: false,  // when true, filters for false values instead of true
)

// standalone
TableFilters::toggleFilter(field: 'is_active', label: null, default: false, negation: false)

relation() / relationFilter()

Adds a select filter scoped to a relationship.

// chained
->relation(
    relationship: 'category',
    field: 'name',
    label: null,
    query: null,        // optional Closure to modify the relationship query
    searchable: true,
    preload: false,
    multiple: false,
)

// standalone
TableFilters::relationFilter(relationship: 'category', field: 'name', label: null, query: null, searchable: true, preload: false, multiple: false)

relationDate() / relationDateFilter()

Adds a date filter scoped to a relationship.

// chained
->relationDate(
    relationship: 'orders',
    field: 'created_at',
    label: null,
    range: true,
    with_time: false,
)

// standalone
TableFilters::relationDateFilter(relationship: 'orders', field: 'created_at', label: null, range: true, with_time: false)

relationNumeric() / relationNumericFilter()

Adds a numeric filter scoped to a relationship.

// chained
->relationNumeric(
    relationship: 'orders',
    field: 'total',
    label: null,
    range: true,
)

// standalone
TableFilters::relationNumericFilter(relationship: 'orders', field: 'total', label: null, range: true)

Chaining

All methods return static, so you can chain as many filters as needed:

TableFilters::make(static::class)
    ->date()
    ->date('updated_at', 'Updated', range: false)
    ->numeric('amount', 'Amount', range: false)
    ->select('status', 'Status', ['draft' => 'Draft', 'published' => 'Published'])
    ->toggle('featured')
    ->relation('author', 'name', searchable: true, preload: true)
    ->relationDate('orders', 'created_at', 'Order Date')
    ->relationNumeric('orders', 'total', 'Order Total')
    ->filters()

License

MIT