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.
All items have an isActive, setActive and setInactive method. The last two allow you to manually determine whether an item is active or not (by default all items are inactive).
Menu::new()->add(Link::to('#', 'Active')->setActive());
<ul>
<li class="active">
<a href="#">Active</a>
</li>
</ul>
If a child item is active, the parent will be considered active too:
Menu::new()->add(
Menu::new()
->add(Html::raw('<a href="#"><img src="/avatar.jpg"></a>')->setActive())
);
<ul>
<li class="active">
<ul>
<li class="active">
<a href="#"><img src="/avatar.jpg"></a>
</li>
</ul>
</li>
</ul>
The Menu class also has a setActive method, but it behaves differently than the method on Link and Html. It accepts a url or a callable as it's parameter, and will use that to determine which underlying items are active.
By providing a url you can set all links that contain or are equal to the url as active. Mixing absolute and relative url's isn't an issue either.
Menu::new()
->link('/', 'Home')
->link('/about', 'About')
->link('/contact', 'Contact')
->setActive('https://example.com/about');
<ul>
<li><a href="/">Home</a></li>
<li class="active"><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
If your base url isn't /, you should provide a request root to improve the active url matching.
Menu::new()
->link('/nl/', 'Home')
->link('/nl/about', 'About')
->link('/nl/contact', 'Contact')
->setActive('https://example.com/nl/about', '/nl');
Calling setActive with a url will recursively traverse through submenus.
If you want more control over which items you want to set active, you can use a callable that returns a boolean.
$menu = Menu::new()
->link('/', 'Home')
->link('/about', 'About')
->link('/contact', 'Contact')
->setActive(function (Link $link) {
return $link->segment(1) === 'about';
});
<ul>
<li><a href="/">Home</a></li>
<li class="active"><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
The callable will not traverse through submenus. If you want to traverse deeper, you'll have to manually add a setActive call with a callable that typehints Menu.
By default, the parent element of active items will receive an active class. If you'd like to override the class name, you can do so with setActiveClass.
Menu::new()
->setActiveClass('is-active')
->add(Link::to('/', 'Home')->setActive());
<ul>
<li class="is-active">
<a href="/">Home</a>
</li>
</ul>
If you want to apply the active class on the a instead of the ul, call the setActiveClassOnLink method when building your menu.
Menu::new()
->setActiveClass('is-active')
->setActiveClassOnLink()
->add(Link::to('/', 'Home')->setActive());
<ul>
<li>
<a href="/" class="is-active">Home</a>
</li>
</ul>
How can I help you explore Laravel packages today?