spatie/menu
Fluent, extensible menu builder for Laravel. Compose navigation with a clean API, render as HTML, and customize output via presenters and macros. Supports active state handling, links, submenus, and easy integration with Blade and your app’s routing.
Begin by installing the package via Composer:
composer require spatie/menu
In Laravel, the service provider auto-registers. Start building a menu using the fluent Menu builder — for example, in a service provider or a dedicated menu class:
use Spatie\Menu\Menu;
use Spatie\Menu\Html\Link;
$menu = Menu::new()
->addItem(Link::to('/', 'Home'))
->addItem(Link::to('/about', 'About'))
->addItem(Link::to('/contact', 'Contact'));
Render it directly in a Blade view:
{!! $menu !!}
The first use case is typically a site-wide main navigation — simple, static links with optional active-state highlighting.
MainMenu) in app/Menus, resolving them via dependency injection or facades for consistency across views.->addItem(Link::to('/admin', 'Admin')->when(fn() => Auth::user()->isAdmin()))
->addItem(Link::to('/dashboard', 'Dashboard')->activeWhen(fn() => request()->is('dashboard*')))
Menu instances:
->addItem((new Menu)
->addItem(Link::to('/settings/profile', 'Profile'))
->addItem(Link::to('/settings/password', 'Password'))
->setLabel('Settings'))
Html::item('<li class="divider"></li>').->setAttributes(['class' => 'nav-item']) or use the attributes() method for per-item markup control.Link::toRoute('home', 'Home') or Link::toAction('HomeController@index', 'Home').Menu renders raw HTML — always trust your generated content. Never inject untrusted user input directly into items. Use Html::raw() only when safe.activeWhen(fn() => request()->is($path)) is a simple string match — use request()->path() or Route::is() for more accurate route matching.Menu Rendering: Submenus auto-render as <ul> wrappers unless customised. Override wrapper classes using ->setWrapperTag('div')->setWrapperAttributes([...]) on the submenu instance.Spatie\Menu\MenuItem to create domain-specific items (e.g., DropdownItem, MenuItemWithIcon) or register custom renderers via Menu::setRenderer().once() if needed.Link::to(...)->addClass('px-4 py-2 text-gray-700') over inline styles. Add activeClass('font-bold text-blue-500') for visual feedback.How can I help you explore Laravel packages today?