leek/filament-right-click
Adds static right-click context menus to Filament table rows and Flowforge Kanban cards. Menu items trigger native Filament actions, so modals, confirmation, authorization, validation, and notifications stay handled by Filament.
Install and register the plugin, then reuse actions you already have.
composer require leek/filament-right-click
php artisan filament:assets
// app/Providers/Filament/AdminPanelProvider.php
$panel->plugin(FilamentRightClickPlugin::make());
Note the version split before you install: v2.x requires Filament 5.6.4+; if you are on Filament v4, pin leek/filament-right-click:^1.5. This is the first thing to check when the plugin "does nothing" after composer require.
Where to look first — the whole public surface is four classes plus two table macros:
Leek\FilamentRightClick\Menu\ContextMenuItem — wraps an Action (or BulkAction via forBulkAction())Leek\FilamentRightClick\Menu\ContextMenuSection — inline labeled group in the same panelLeek\FilamentRightClick\Menu\ContextMenuSeparatorLeek\FilamentRightClick\Menu\ContextMenuSubmenu — flyout (v1.5+)Table::contextMenuActions() / Table::contextMenuBulkActions()First use case: take a table that already has ->actions([DeleteAction::make(), EditAction::make()]) and add a right-click menu that mounts the same actions. Because the items wrap native Filament actions, confirmation modals, policies, notifications and redirects come along for free — there is no new authorization layer to learn.
->contextMenuActions([
ContextMenuItem::for(Action::make('edit')->action(fn ($record) => /* ... */))
->icon(Heroicon::PencilSquare),
ContextMenuSeparator::make(),
ContextMenuItem::for(DeleteAction::make())->color('danger'),
])
Since v1.4 you can skip ->icon()/->color() on the item entirely — they fall back to the wrapped action's icon and color (non-string custom palette colors are dropped, so use named colors).
Extract action definitions, don't duplicate them. The common failure mode is defining "archive" once in ->actions() and again in contextMenuActions(), then watching them drift. Put the action in a private static method or a dedicated Actions class and call it from both places:
public static function archiveAction(): Action
{
return Action::make('archive')
->requiresConfirmation()
->authorize('archive')
->action(fn ($record) => $record->archive());
}
->actions([self::archiveAction(), ...])
->contextMenuActions([ContextMenuItem::for(self::archiveAction())])
Use mirrors() (v2) for per-row entries. The menu label/icon/color is static client-side metadata — it cannot know that row 42 is archived and can't be archived again. ContextMenuItem::mirrors('rowAction') makes the entry appear only on rows where the named row action renders, so hidden/unauthorized actions drop out of the menu. Dangling separators are cleaned up, and sections/submenus disappear once all their entries are hidden. This is the single most important pattern for menus that contain conditional items.
Prefer submenus over long flat menus. ContextMenuSection is an inline labeled group — it does not collapse. If you have eight status options, use ContextMenuSubmenu::make([...])->label('Status') so the root menu stays short. Submenus nest arbitrarily and keep the same action mounting path.
Bulk workflow: select first, then right-click. Behaviour is: if the right-clicked row is already in the selection, the bulk menu opens using the live Filament selection (including select-all-across-pages). If it isn't selected, the single-record menu opens instead. Design bulk menus around this — users must select rows before right-clicking, which is not obvious. Consider keeping a bulk item that says "Archive Selected (N)" with a count in the label so the selection state is legible.
Flowforge cards. Register contextMenuCardActions() on the board, not on the table. It's a macro added only when Relaticle\Flowforge\Board exists, so guard nothing — just don't call it if you don't have Flowforge. Card actions mount through mountAction(name, [], { recordKey }).
Third-party actions compose for free. TriggerWorkflowAction from leek/filament-workflows drops straight into contextMenuActions() and brings its own filtered modal. Treat the context menu as a placement mechanism for actions, not a place to build bespoke behaviour.
mirrors()). The package explicitly does no client-side policy decision: if the action is hidden, disabled or unauthorized, Filament refuses to mount it, the menu closes, and the user sees nothing. That's correct and safe, but it reads as a broken menu item. Use mirrors() or keep a single canonical action per entry.->actions() and contextMenuActions(), or you'll get confusing collisions.php artisan filament:assets after every upgrade. Assets are loadedOnRequest() and only requested by tables that actually configure a context menu, so a stale asset build looks like "plugin registered but nothing happens."data-filament-right-click-record-config, -bulk-config, -flowforge-card-config (plus legacy data-filament-right-click-config), row keys from Filament's wire:key, card keys from data-card-id. Changing these silently breaks mounting.->actions() as the accessible path; treat right-click as a power-user accelerator, not the only route.data-* attribute on the table root, then check the network tab for the mountTableAction / mountAction Livewire call. A 403/silent no-op there is almost always an authorization or visible() predicate, not a JS bug.ContextMenu key and Shift+F10 open the menu for the focused/last-hovered row; arrow keys, Enter/Space and Escape all work — worth mentioning in your in-app help so keyboard users discover it.ContextMenuItem/Section/Separator/Submenu means publishing assets and honouring the DOM contract above rather than subclassing the item classes.How can I help you explore Laravel packages today?