agroezinger / filament-navigation-enhanced
Adds collapsible child-item support to the Filament sidebar navigation.
Package info
github.com/agroezinger/filament-navigation-enhanced
Language:Blade
pkg:composer/agroezinger/filament-navigation-enhanced
Requires
- php: ^8.2
- filament/filament: ^5.0
README
Adds collapsible child-item support to the Filament v5 sidebar navigation. A parent item becomes an expand/collapse toggle; its children are revealed in an animated sub-list. The group auto-expands whenever a child is active.
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.2 |
| filament/filament | ^5.0 |
Installation
Via Composer (Packagist)
composer require agroezinger/filament-navigation-enhanced
Publish the view override
The package ships a replacement for Filament's sidebar/item component. Publish it once so Filament picks it up:
php artisan vendor:publish --tag=navigation-enhanced-views
This copies the view to resources/views/vendor/filament-panels/components/sidebar/item.blade.php.
Usage
1. Register the plugin
Add NavigationEnhancedPlugin to every panel that should use the feature:
use Agroezinger\FilamentNavigationEnhanced\NavigationEnhancedPlugin; public function panel(Panel $panel): Panel { return $panel // ... ->plugins([ NavigationEnhancedPlugin::make(), ]); }
The plugin itself has no configuration options — registering it documents intent and allows future configuration hooks.
2. Add the trait to a parent Page or Resource
use Agroezinger\FilamentNavigationEnhanced\Concerns\HasNavigationChildren; use Filament\Navigation\NavigationItem; class SettingsPage extends Page { use HasNavigationChildren; protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-cog-6-tooth'; protected static string|\UnitEnum|null $navigationGroup = 'Einstellungen'; protected static ?string $navigationLabel = 'Einstellungen'; public static function getNavigationChildItems(): array { return [ NavigationItem::make('Allgemein') ->url(static::getUrl()) ->icon('heroicon-o-cog-6-tooth') ->isActiveWhen(fn() => request()->routeIs('filament.club.pages.settings.general')), NavigationItem::make('Abteilungen') ->url(DepartmentResource::getUrl('index')) ->icon('heroicon-o-rectangle-stack') ->isActiveWhen(fn() => request()->routeIs('filament.club.resources.departments.*')), NavigationItem::make('Benutzer') ->url(UserResource::getUrl('index')) ->icon('heroicon-o-users') ->isActiveWhen(fn() => request()->routeIs('filament.club.resources.users.*')), ]; } }
3. Suppress child items from the top-level navigation
Resources and Pages that appear as children should not register themselves as standalone sidebar items. Override shouldRegisterNavigation() on the Resource:
class DepartmentResource extends Resource { public static function shouldRegisterNavigation(): bool { return false; } }
For a child Page, set:
protected static bool $shouldRegisterNavigation = false;
4. Active-state detection
Use request()->routeIs() with a wildcard to match all pages of a resource (index, create, edit):
NavigationItem::make('Abteilungen') ->isActiveWhen(fn() => request()->routeIs('filament.{panel}.resources.{resource-slug}.*')),
For a single Page, match the exact route name:
NavigationItem::make('Allgemein') ->isActiveWhen(fn() => request()->routeIs('filament.{panel}.pages.{page-slug}')),
To find the exact route names for your panel, run:
php artisan route:list --name="filament.{panel}" --json \ | php -r "foreach(json_decode(file_get_contents('php://stdin'),true) as \$r) echo \$r['name'].PHP_EOL;"
How it works
The package publishes a custom sidebar/item Blade component that extends Filament's default one. When a NavigationItem carries child items (set via $item->childItems([...])), the component renders a <button> toggle instead of an <a> link, and wraps the children in an Alpine.js-powered <ul> with enter/leave transitions.
HasNavigationChildren::getNavigationItems() wraps the parent's items and calls childItems() on each with the return value of getNavigationChildItems(). The parent item auto-expands on load when $active || $activeChildItems is true.
Items without children fall through to Filament's original rendering path unchanged.
License
MIT