PHPackages                             sixteenhands/filament-dynamic-filter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. sixteenhands/filament-dynamic-filter

ActiveLibrary[Search &amp; Filtering](/categories/search)

sixteenhands/filament-dynamic-filter
====================================

Dynamic table filters for Filament with caching, indicators and panel access control

v0.1.9(2mo ago)06[4 PRs](https://github.com/16hands/filament-dynamic-filter/pulls)MITPHPPHP ^8.2CI passing

Since Jan 30Pushed 1mo agoCompare

[ Source](https://github.com/16hands/filament-dynamic-filter)[ Packagist](https://packagist.org/packages/sixteenhands/filament-dynamic-filter)[ Docs](https://github.com/16hands/filament-dynamic-filter)[ GitHub Sponsors](https://github.com/16hands)[ RSS](/packages/sixteenhands-filament-dynamic-filter/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (13)Versions (15)Used By (0)

Filament Dynamic Filter
=======================

[](#filament-dynamic-filter)

[![Latest Version on Packagist](https://camo.githubusercontent.com/42d1d5d0cbb1267ea8056e8063b14a778afaa46cefb76ba662ed503b067d56d8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7369787465656e68616e64732f66696c616d656e742d64796e616d69632d66696c7465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sixteenhands/filament-dynamic-filter)[![Total Downloads](https://camo.githubusercontent.com/cd7e71f81e360b26e6a6705146da139228edf7b3cad4215e4ed98116fbb3c77a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7369787465656e68616e64732f66696c616d656e742d64796e616d69632d66696c7465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sixteenhands/filament-dynamic-filter)

Dynamic select filters for Filament tables. For direct columns, options come from the current table query; relationship filters query the related model by default.

The Problem
-----------

[](#the-problem)

If you've used DataTables before, you'll remember the column header filters that automatically populated with values from the table data. Filament's built-in `SelectFilter` requires you to manually define options or query them separately from an entire table/model.

This becomes a real pain with relationship managers. Say you have an `Order` resource with a `LineItems` relation manager. You want to filter line items by product name, but only show products that actually exist in *this order's*line items — not every product in the database.

This package gives you filters that pull their options from the current table query for direct columns, respecting any existing filters or scopes already applied. Relationship filters default to querying the related model directly, but you can override this with `optionsQuery` when you need custom constraints.

Installation
------------

[](#installation)

```
composer require sixteenhands/filament-dynamic-filter
```

Usage
-----

[](#usage)

```
use Filament\Tables\Contracts\HasTable;
use Illuminate\Database\Eloquent\Builder;
use SixteenHands\FilamentDynamicFilter\DynamicFilter;

public function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('packhouse.packhouse_name'),
            TextColumn::make('grade'),
            TextColumn::make('variety.variety_name'),
        ])
        ->filters([
            // Basic filter - column path matches query column
            DynamicFilter::make(
                name: 'packhouse_filter',
                column: 'packhouse.packhouse_name',
                queryColumn: 'packhouses.packhouse_name'
            ),

            // With options
            DynamicFilter::make(
                name: 'grade_filter',
                column: 'grade',
                queryColumn: 'grade',
                label: 'Grade',
                searchable: true
            ),

            // With custom option labels (booleans, enums, etc.)
            DynamicFilter::make(
                name: 'active_filter',
                column: 'is_active',
                queryColumn: 'is_active',
                optionsMap: [
                    1 => 'Active',
                    0 => 'Inactive',
                ],
            ),

            // With a custom options query
            DynamicFilter::make(
                name: 'status_filter',
                column: 'status',
                queryColumn: 'status',
                optionsQuery: fn (HasTable $livewire, Builder $query) => $query->whereNotNull('status')
            ),
        ]);
}
```

### Multiple Selection

[](#multiple-selection)

```
DynamicFilter::multiple(
    name: 'variety_filter',
    column: 'variety.variety_name',
    queryColumn: 'varieties.variety_name',
    searchable: true
)
```

### Lazy Option Loading (Searchable Only)

[](#lazy-option-loading-searchable-only)

When `lazy: true` and `searchable: true`, options are empty until the user types. Search results are fetched on demand.

**Large lists (recommended):**

```
DynamicFilter::make(
    name: 'customer_filter',
    column: 'customer.name',
    queryColumn: 'customers.name',
    searchable: true,
    lazy: true
)
```

**Short lists (preload is fine):**

```
DynamicFilter::make(
    name: 'status_filter',
    column: 'status',
    queryColumn: 'status',
    searchable: true
)
```

### Relationship Filters

[](#relationship-filters)

For filtering through relationships using `whereHas`:

```
DynamicFilter::relationship(
    name: 'supplier_filter',
    column: 'supplier.name',
    relationship: 'supplier',
    relationshipColumn: 'name',
    multiple: true
)
```

By default, relationship filters query the related model directly (no joins) so options and search work out of the box. You can override this with `optionsQuery` if you need custom constraints:

```
DynamicFilter::relationship(
    name: 'supplier_filter',
    column: 'supplier.name',
    relationship: 'supplier',
    relationshipColumn: 'name',
    optionsQuery: fn (HasTable $livewire, Builder $query) => $query
        ->getModel()
        ->supplier()
        ->getRelated()
        ->newQuery()
        ->where('is_active', true)
)
```

### Panel Access Control

[](#panel-access-control)

Restrict filters to specific panels:

```
DynamicFilter::make(
    name: 'admin_only_filter',
    column: 'internal_code',
    queryColumn: 'internal_code',
    panels: ['admin'] // Only shows in admin panel
)
```

How It Works
------------

[](#how-it-works)

The filter grabs the current table query (with all existing filters/scopes applied), plucks distinct values for the specified column when possible, and uses those as select options. Results are cached per column with a configurable TTL and scope.

Handles Carbon dates and PHP enums automatically — dates display as `d/m/Y` but filter as `Y-m-d`, enums use their `getLabel()` method for display.

Parameters
----------

[](#parameters)

**`DynamicFilter::make()`** and **`DynamicFilter::multiple()`**

ParameterTypeDescription`name`stringFilter name (must be unique)`column`stringDot-notation path to pluck from results (e.g. `relation.field`)`queryColumn`stringDatabase column for the where clause (e.g. `table.field`)`placeholder`?stringSelect placeholder text`label`?stringFilter label`searchable`boolEnable search in select (default: false)`lazy`boolDefer options until search (requires `searchable`; default: false)`panels`?arrayRestrict to specific panel IDs`optionsMap`?arrayMap of raw values to display labels`formatOption`?callableFormatter callback: `fn ($value): array`optionsQuery`?callableProvide a custom options Builder or Collection: `fn (HasTable $livewire, Builder $query)` (distinct/limit apply to Builders)**`DynamicFilter::relationship()`** adds:

ParameterTypeDescription`relationship`stringRelationship name for whereHas`relationshipColumn`stringColumn within the relationship`multiple`boolAllow multiple selection (default: false)It also supports all base parameters above (including `optionsQuery`).

Configuration
-------------

[](#configuration)

Publish the config if you'd like to tune caching:

```
php artisan vendor:publish --tag="filament-dynamic-filter-config"
```

```
return [
    'cache_ttl' => 300,
    'max_options' => null,
    'cache_scope' => 'user', // user | tenant | global
];
```

When using `tenant` scope, provide a tenant key or resolver in your config (otherwise caching is skipped for safety):

```
'tenant_key' => null,
'tenant_resolver' => fn () => tenant('id'),
```

Caching Notes
-------------

[](#caching-notes)

- Options are cached per column using a distinct query when possible.
- If a distinct query fails, the filter falls back to `$query->get()->pluck($column)`.
- Exceptions do not write to cache; they return an empty options list.
- `max_options` caps the number of options returned.

Requirements
------------

[](#requirements)

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

License
-------

[](#license)

MIT

Credits
-------

[](#credits)

[16Hands](https://16hands.co.nz)

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance87

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

10

Last Release

87d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/c55c4edc852b3d7590f1e23a488304666be99e97a58443810a4358c8f2c1d351?d=identicon)[16hands](/maintainers/16hands)

---

Top Contributors

[![16hands](https://avatars.githubusercontent.com/u/570051?v=4)](https://github.com/16hands "16hands (17 commits)")

---

Tags

laravelfiltertablesfilamentsixteenhandsfilament-dynamic-filter

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/sixteenhands-filament-dynamic-filter/health.svg)

```
[![Health](https://phpackages.com/badges/sixteenhands-filament-dynamic-filter/health.svg)](https://phpackages.com/packages/sixteenhands-filament-dynamic-filter)
```

###  Alternatives

[webbingbrasil/filament-advancedfilter

Advanced filter component for filament admin.

146132.1k](/packages/webbingbrasil-filament-advancedfilter)[webbingbrasil/filament-datefilter

Date filter component for filament tables.

1479.4k](/packages/webbingbrasil-filament-datefilter)[codewithdennis/filament-price-filter

A simple and customizable price filter for FilamentPHP, allowing users to easily refine results based on specified price ranges.

163.2k](/packages/codewithdennis-filament-price-filter)[tapp/filament-value-range-filter

Filament country code field.

2362.2k](/packages/tapp-filament-value-range-filter)[kainiklas/filament-scout

Filament Plugin to integrate Scout into Global Search and Table Search.

3573.3k](/packages/kainiklas-filament-scout)[pos-lifestyle/laravel-nova-date-range-filter

A Laravel Nova date range filter.

16179.1k](/packages/pos-lifestyle-laravel-nova-date-range-filter)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
