Table Toggle Column with Custom Action

The Problem
By default, Filament's ToggleColumn immediately updates the database when clicked, without any confirmation or ability
to add custom validation logic. This becomes problematic when you need to:
- Show a confirmation modal before making the change
- Validate business rules before allowing the toggle
- Prevent certain records from being toggled based on specific conditions
- Provide user feedback when an action cannot be completed
For the sake of the example, let's prevent staff from changing chicken items and require confirmation before changing availability status of any product.
The Solution
The solution involves customizing the behaviour of the ToggleColumn updating process and then invoking a custom
action - which must be hidden from the user interface with a class.
1. We create a dedicated file for this whole mechanism
This class defines three key methods:
action(): Creates the Filament action that we will place on the desired page.updateStateUsing(): Replace theToggleColumnsaving state logic to invoke our custom action.handleAction(): Contains the custom business logic and validation.
<?php
namespace App\Filament\Resources\MenuItems\Actions;
use App\Models\MenuItem;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\Page;
class IsAvailable
{
protected const string Action_ID = 'is_available_toggle';
public static function action(): Action
{
return Action::make(static::Action_ID)
->action(static::handleAction(...))
// You may have a custom form schema if needed, and get that in the arguments' injection
// ->schema([
// TextInput...
// ])
->requiresConfirmation()
->modalHeading(fn($arguments) => 'Change Availability of: ' . data_get($arguments, 'record.name') . '?')
->extraAttributes(['class' => 'hidden']);
}
public static function updateStateUsing(Page $livewire, MenuItem $record, $state): void
{
$livewire->mountAction(static::Action_ID, [
'record' => $record,
'state' => $state,
]);
}
public static function handleAction(Page $livewire, Action $action, array $arguments): void
{
$state = data_get($arguments, 'state');
/** @var MenuItem $record */
$record = $arguments['record'];
// Prevent changing availability of chicken items, as an example business rule
if (str($record->name)->contains(['Chicken', 'chicken'])) {
Notification::make()
->title('You cannot change availability of chicken items.')
->danger()
->send();
$livewire->unmountAction();
$action->halt();
}
$record->is_available = $state;
$record->save();
}
}
2. Register the Action on the page
Add the action to the page's header actions - it will be hidden but accessible programmatically:
<?php
namespace App\Filament\Resources\MenuItems\Pages;
use App\Filament\Resources\MenuItems\Actions\IsAvailable;
use Filament\Actions\CreateAction;
use App\Filament\Resources\MenuItems\MenuItemResource;
use Filament\Resources\Pages\ListRecords;
class ListMenuItems extends ListRecords
{
protected static string $resource = MenuItemResource::class;
protected function getHeaderActions(): array
{
return [
IsAvailable::action(),
CreateAction::make(),
];
}
}
3. Update the Table Column
Use ToggleColumn that uses the custom action to handle state updates:
<?php
namespace App\Filament\Resources\MenuItems\Tables;
use App\Filament\Resources\MenuItems\Actions\IsAvailable;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ToggleColumn;
use Filament\Tables\Table;
class MenuItemTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable(),
TextColumn::make('price')
->money('USD')
->sortable(),
ToggleColumn::make('is_available')
->label('Is available?')
->updateStateUsing(IsAvailable::updateStateUsing(...)),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
Now when users click the toggle, the custom action gets invoked, and we can customize however we see fit!
Multi-Login Authentication - Email, Username, or SSN
How to implement flexible user authentication allowing login with email, username, or social security number.
Pragmatic Roles and Permissions in FilamentPHP
Learn how to implement a clean and maintainable roles and permissions system in FilamentPHP using Laravel Ladder, with practical examples for multi-role restaurant management.