spatie/laravel-menu
Build HTML menus in Laravel with a fluent API. Generate links from routes/actions/URLs, group items, add attributes/classes, and automatically set the active item from the current request. Extensible via macros; renders to HTML ready for Blade.
Pros:
Menu::new()->action(...)), reducing cognitive load for developers familiar with Laravel’s query builder or Blade components.action(), route()), authorization (actionIfCan()), and request handling (setActiveFromRequest()), reducing friction for existing codebases.Menu::macro('admin', ...)), promoting DRY principles and consistency.Illuminate\Contracts\Support\Htmlable, enabling direct Blade rendering ({!! Menu::main() !!}) or integration with Laravel’s view composers.Cons:
setActiveFromRequest() relies on Laravel’s Request facade). May complicate adoption in non-Laravel contexts (though this is intentional).Stack Compatibility:
spatie/menu core package + Laravel components). No heavy frameworks or external services.Migration Path:
3.x and migrate incrementally.foreach ($routes as $route)) with Menu::macro() definitions. Example:
// Before: Manual Blade loop
@foreach ($navItems as $item)
<a href="{{ route($item['route']) }}" class="{{ request()->routeIs($item['route']) ? 'active' : '' }}">
{{ $item['label'] }}
</a>
@endforeach
// After: Macro-based
Menu::macro('primary', function () {
return Menu::new()
->action('HomeController@index', 'Home')
->action('ProductsController@index', 'Products')
->setActiveFromRequest();
});
Spatie\Menu\Laravel\Facades\Menu in unit tests.Low Risk:
laravel-permission) are widely adopted.Moderate Risk:
// Hypothetical: Dynamic menu from DB
Menu::macro('dynamic', function () {
return Menu::new()
->items(MenuItem::where('visible', true)->get()->map(fn ($item) =>
Menu::item()
->url($item->path)
->title($item->name)
));
});
actionIfCan() for each item) could impact rendering time. Profile with tideways/xhprof or Laravel Debugbar.Menu::cacheFor() or Menu::cacheWhile() for static menus.Key Questions:
actionIfCan() simplifies this; otherwise, custom logic may be needed.{!! Menu::main() !!}).wire:navigate with menu items or render directly in components.Assessment Phase:
Pilot Phase:
spatie/laravel-menu.Menu::macro('primary', ...)) and test in a non-critical view.setActiveFromRequest()).action(), route()).actionIfCan()).Full Rollout:
Menu::macro() for all new menus.Custom Extensions (if needed):
Spatie\Menu\Menu or create a custom MenuItem class.Menu::items() with a collection from an external source.translate() method to macros or use Laravel’s trans() helper in menu items.actionIfCan().setActiveFromRequest() uses Laravel’s Request facade.How can I help you explore Laravel packages today?