Desired Feature #
Using a header button, the ‘company’ filter is toggled on and off with a custom option (“Google”).
Multiple Selection Filter Example #

/*
Company filter is applied to the 'company' field on the Company model
Table function defined in the CompanyResource.php file as created by Filament
*/
namespace App\Filament\Resources;
public static function table(Table $table): Table
{
return $table
->headerActions([
Tables\Actions\Action::make('google_filter')
->badge()
->label('Google')
->icon(fn (ListRecords|TableWidget $livewire) => in_array(Companies::Google->value, Arr::get($livewire->tableFilters ?? [], 'company.values', []))
? 'heroicon-s-funnel'
: 'heroicon-o-funnel'
)
->action(fn (ListRecords|TableWidget $livewire) => self::buttonFilterApply($livewire, 'company', Companies::Google->value)),
Tables\Actions\Action::make('apple_filter')
->badge()
->label('Apple')
->icon(fn (ListRecords|TableWidget $livewire) => in_array(Companies::Apple->value, Arr::get($livewire->tableFilters ?? [], 'company.values', []))
? 'heroicon-s-funnel'
: 'heroicon-o-funnel'
)
->action(fn (ListRecords|TableWidget $livewire) => self::buttonFilterApply($livewire, 'company', Companies::Apple->value)),
])
->filters([
SelectFilter::make('company')
->multiple()
->native(false)
->options(Companies::class),
])
->columns([
TextColumn::make('name'),
TextColumn::make('job_title'),
TextColumn::make('location'),
TextColumn::make('company'),
]);
}
private static function buttonFilterApply(ListRecords|TableWidget $livewire, string $filter, string $option): void
{
$filter_value = (array) Arr::get($livewire->tableFilters ?? [], $filter, []);
if (empty($filter_value)) {
return;
}
if (in_array($option, $filter_value['values'])) {
$livewire->tableFilters[$filter]['values'] = array_diff($filter_value['values'], [$option]);
} else {
$livewire->tableFilters[$filter]['values'][] = $option;
}
}
Single Selection Filter Example #

namespace App\Filament\Resources;
public static function table(Table $table): Table
{
return $table
->headerActions([
Tables\Actions\Action::make('google_filter')
->badge()
->label('Google')
->icon(fn (ListRecords|TableWidget $livewire) => Arr::get($livewire->tableFilters ?? [], 'company.value') === Companies::Google->value
? 'heroicon-s-funnel'
: 'heroicon-o-funnel'
)
->action(fn (ListRecords|TableWidget $livewire) => self::buttonFilterApply($livewire, 'company', Companies::Google->value)),
])
->filters([
SelectFilter::make('company')
->native(false)
->options(Companies::class),
])
->columns([
TextColumn::make('name'),
TextColumn::make('job_title'),
TextColumn::make('location'),
TextColumn::make('company'),
]);
}
private static function buttonFilterApply(ListRecords|TableWidget $livewire, string $filter, string $option): void
{
$filter_value = Arr::get($livewire->tableFilters ?? [], $filter);
if (empty($filter_value)) {
return;
}
$new_value = Arr::get($filter_value, 'value') === $option ? '' : $option;
$livewire->tableFilters[$filter] = ['value' => $new_value];
}
Support #
Companies Enum #
/*
Optional enum class for additional clarity above
*/
use Filament\Support\Contracts\HasLabel;
enum Companies: string implements HasLabel
{
case Google = 'Google';
case Apple = 'Apple';
case Yahoo = 'Yahoo';
public function getLabel(): ?string
{
return $this->name;
}
}
Livewire Type #
In order for LaraStan to be happy, we need the correct livewire type applied to our icon() & action() methods on our header action - types that have the $tableFilters property.
That Filament class is Filament\Resources\Pages\ListRecords, however, in the event you utilize this table in a table widget you’ll need to union that
type with Filament\Widgets\TableWidget, hence ListRecords|TableWidget $livewire.