spatie/laravel-menu
Build HTML menus in Laravel with a fluent API. Add links via routes/actions/URLs, customize attributes and classes, and automatically set active items from the current request. Includes macros for reusable menu builders.
Pros:
Menu::new()->action()->addIfCan()) aligns with modern PHP/Laravel conventions, improving readability and maintainability.addIfCan, setActiveFromRequest), enabling tailored solutions without forking.Cons:
Route, Gate, Auth) for full functionality. May complicate adoption in non-Laravel projects or hybrid architectures.menus table). Workarounds (e.g., Menu::fromModel() via macros) are manual.Stack Compatibility:
bcmath, fileinfo).Migration Path:
// Before: Manual Blade logic
<nav>
@if (request()->is('dashboard'))
<a href="/dashboard">Dashboard</a>
@endif
</nav>
// After: Using spatie/laravel-menu
<nav>{!! Menu::macro('main')->activeFromRequest() !!}</nav>
addIfCan, setActiveFromRequest).Technical Risk:
setActiveFromRequest) may require forks or extensions.Dynamic vs. Static Menus:
setActiveFromRequest() and addIfCan are critical.Localization/i18n:
trans() helper or a macro to wrap labels (e.g., Menu::macro('nav')->label(trans('menu.home'))).Headless/API Use Cases:
Performance:
Cache::remember('menu', ...)) to avoid redundant database/auth checks.Testing:
Menu facade in unit tests with mocked requests/gates.expect()->html() or Pest’s assertions.Extensibility:
Spatie\Menu\MenuItem.Deployment:
Core Stack:
composer require spatie/laravel-menu; no additional dependencies.Extended Stack:
Gate, Policy, and Auth systems via addIfCan and setActiveFromRequest.route(), action(), and named routes (e.g., Menu::new()->toRoute('dashboard')).<a href="{{ Menu::main()->activeFromRequest()->first()->url }}"
class="{{ Menu::main()->activeFromRequest()->first()->isActive ? 'active' : '' }}">
wire:click or x-data to handle dynamic menu interactions (e.g., dropdowns) while keeping menu logic server-side.Non-Laravel Components:
// Controller
public function menu()
{
return response()->json(Menu::main()->toArray());
}
menus table and use a macro to fetch items:
Menu::macro('fromDatabase', function () {
return Menu::new()->items(Menu::Item::fromCollection(Menu::query()->get()));
});
Assessment Phase:
Pilot Phase:
spatie/laravel-menu:
// app/Providers/AppServiceProvider.php
public function boot()
{
Menu::macro('footer', function () {
return Menu::new()
->add('Home', 'home')
->add('About', 'about')
->add('Contact', 'contact');
});
}
<footer>{!! Menu::footer() !!}</footer>
Scaling Phase:
setActiveFromRequest, addIfCan):
Menu::macro('admin', function () {
return Menu::new()
->addIfCan('Dashboard', 'dashboard', 'view dashboard')
->addIfCan('Users', 'users.index', 'view users')
->setActiveFromRequest();
});
// Use Laravel's Gate
Menu::macro('userMenu', function () {
return Menu::new()
->addIfCan('Profile', 'profile.edit', 'edit profile')
->addIfCan('Settings', 'settings.show', 'view settings');
});
Optimization Phase:
How can I help you explore Laravel packages today?