Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Context Menu Laravel Package

aymanalhattami/filament-context-menu

Add right‑click context menus to Filament pages and table cells using Filament Actions. Works on resource and custom pages, supports dividers, dark/light mode, and LTR/RTL. Includes Refresh, Go Back, and Go Forward actions. Filament v3–v5.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require aymanalhattami/filament-context-menu
    

    Ensure compatibility with your Filament version (3.x, 4.x, or 5.x).

  2. First Use Case: Add the PageHasContextMenu trait to a Filament page (e.g., ListRecords or ViewRecord):

    use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
    
    class ListUsers extends ListRecords
    {
        use PageHasContextMenu;
    
        public function getContextMenuActions(): array
        {
            return [
                Action::make('Refresh Page')
                    ->action(fn () => $this->refresh())
            ];
        }
    }
    

    Right-click anywhere on the page to test the context menu.


Implementation Patterns

Page-Level Context Menus

  1. Dynamic Actions: Use getContextMenuActions() to return an array of Filament Action objects. Leverage Filament’s built-in actions (e.g., CreateAction, EditAction) or custom actions:

    public function getContextMenuActions(): array
    {
        return [
            CreateAction::make()->model(User::class),
            Action::make('Custom Action')
                ->icon('heroicon-o-pencil')
                ->action(fn () => $this->customLogic())
        ];
    }
    
  2. Conditional Logic: Dynamically filter actions based on user roles or record state:

    public function getContextMenuActions(): array
    {
        $actions = [/* default actions */];
        if ($this->auth()->user()->can('delete')) {
            $actions[] = DeleteAction::make()->record($this->record);
        }
        return $actions;
    }
    
  3. Dividers: Use ContextMenuDivider to group actions:

    return [
        Action::make('Group 1'),
        ContextMenuDivider::make(),
        Action::make('Group 2'),
    ];
    

Table Cell Context Menus

  1. Column Integration: Replace standard columns with context-menu-enabled variants (e.g., ContextMenuTextColumn):

    Table::make(User::class)
        ->columns([
            ContextMenuTextColumn::make('name')
                ->getContextMenuActions(fn ($record) => [
                    Action::make('Edit Name')
                        ->action(fn () => $record->update(['name' => 'Updated']))
                ]),
        ]);
    
  2. Record-Specific Actions: Pass the record to getContextMenuActions for dynamic actions:

    ContextMenuTextColumn::make('status')
        ->getContextMenuActions(fn ($record) => [
            Action::make('Toggle Active')
                ->icon($record->active ? 'heroicon-o-x-circle' : 'heroicon-o-check-circle')
                ->action(fn () => $record->update(['active' => !$record->active])),
        ]);
    
  3. Bulk Actions: Combine with table bulk actions for consistency:

    Table::make(User::class)
        ->columns([
            ContextMenuCheckboxColumn::make('select'),
            // ...
        ])
        ->actions([
            Action::make('Bulk Delete')
                ->requiresConfirmation()
                ->action(fn () => User::whereIn('id', $this->getSelectedRecords())->delete()),
        ]);
    

Custom Pages and Workflows

  1. Dashboard Integration: Add context menus to custom dashboard widgets or pages:

    class CustomDashboard extends Page
    {
        use PageHasContextMenu;
    
        public function getContextMenuActions(): array
        {
            return [
                Action::make('Reset Dashboard')
                    ->action(fn () => $this->resetLayout()),
            ];
        }
    }
    
  2. Modal Actions: Use modal-based actions for complex operations:

    Action::make('Advanced Edit')
        ->modalContent(fn ($record) => view('filament.modals.advanced-edit', ['record' => $record]))
        ->action(fn () => $this->handleAdvancedEdit($record)),
    
  3. Nested Resources: Extend context menus for nested resource pages (e.g., EditPost with EditComment sub-actions):

    class EditPost extends EditRecord
    {
        use PageHasContextMenu;
    
        public function getContextMenuActions(): array
        {
            return [
                Action::make('Edit Comments')
                    ->url(fn () => route('filament.admin.resources.comments.edit', $this->record->comments->first())),
            ];
        }
    }
    

Gotchas and Tips

Common Pitfalls

  1. Action Registration Timing:

    • Issue: Actions may not appear if getContextMenuActions() is defined as static but relies on instance properties (e.g., $this->record).
    • Fix: Use instance methods or pass dependencies:
      public function getContextMenuActions(): array
      {
          return $this->resolveActions($this->record); // Custom method
      }
      
  2. Duplicate Actions:

    • Issue: Accidental duplication of actions (e.g., in both page and table contexts).
    • Fix: Use unique action keys or validate actions in getContextMenuActions().
  3. Dark Mode Conflicts:

    • Issue: Custom styling may break dark/light mode compatibility.
    • Fix: Use Filament’s built-in classes (e.g., dark:bg-gray-800) or override via CSS:
      .filament-context-menu {
          background: var(--color-gray-100);
      }
      .filament-context-menu.dark {
          background: var(--color-gray-800);
      }
      

Debugging Tips

  1. Inspect Menu Content: Use browser dev tools to check if actions are rendered:

    console.log(document.querySelectorAll('.filament-context-menu li'));
    
  2. Disable Globally: Temporarily disable the menu via .env:

    CONTEXT_MENU_ENABLED=false
    

    Or override in the page:

    public static bool $contextMenuEnabled = false;
    
  3. Action Logging: Add debug logs to getContextMenuActions() to verify action resolution:

    public function getContextMenuActions(): array
    {
        $actions = [
            Action::make('Debug')
                ->action(fn () => Log::debug('Context menu triggered')),
        ];
        Log::debug('Context menu actions:', $actions);
        return $actions;
    }
    

Extension Points

  1. Custom Styling: Override the menu’s Blade template (resources/views/vendor/filament-context-menu/menu.blade.php) or use CSS variables:

    .filament-context-menu {
        --context-menu-width: 200px;
        --context-menu-padding: 0.5rem;
    }
    
  2. Event Listeners: Listen for context menu events (e.g., context-menu:opening):

    public function register()
    {
        FilamentContextMenu::listen('context-menu:opening', fn ($event) => {
            Log::info('Menu opened for page:', $event->page);
        });
    }
    
  3. Localization: Translate action labels using Filament’s translation system:

    Action::make(__('filament-context-menu::actions.refresh'))
        ->action(fn () => $this->refresh()),
    
  4. Keyboard Shortcuts: Combine with Filament’s keyboard shortcuts for power users:

    public static function getNavigationShortcuts(): array
    {
        return [
            shortcut('r', fn () => redirect()->refresh()),
        ];
    }
    

Performance Considerations

  1. Lazy-Load Actions: Defer action resolution until the menu is opened:

    public function getContextMenuActions(): array
    {
        return [
            Action::make('Lazy Action')
                ->action(fn () => $this->resolveLazyAction()),
        ];
    }
    
  2. Memoization: Cache resolved actions if they’re computationally expensive:

    protected ?array $contextMenuActions = null;
    
    public function getContextMenuActions(): array
    {
        return $this->contextMenuActions ??= $this->resolveActions();
    }
    
  3. Avoid Heavy Dependencies: Keep getContextMenuActions() lightweight. Offload complex logic to separate methods or services.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky