A modern package to generate html menus

Virtually every website displays some sort of menu. Generating html menus might seem simple, but it can become complex very quickly. Not only do you have to render some basic html, but you also have to manage which item is active. If a menu has a submenu you’ll also want the parents of an active item to be active. Sometimes you want to insert some html between menu items.

There are some packages out there that can help generating menus, but most of them have a messy API or have become victims of feature creep. Thanks why we decided to create our own modern menu package that has a beautiful API to work with. We have provided full documentation containing lots of examples. In this post I’d like to walk you through it.

Generating menus

Though the main package is framework agnostic, we are going to assume in the following examples you are going to use it in a Laravel app. Let’s start simple. Image you want to generate this menu:

<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>

Here’s the code to do that:

$menu = Menu::new()
->add(Link::to('/', 'Home'))
->add(Link::to('/about', 'About'));

The menu can be rendered by calling render on it. Menu also implements __toString so it’s probably more practically to just output the menu in a view.

// in a blade view
Here is the menu: {!! $menu !!}

Let’s try something more complicated. Image you want to render this.

<ul>
<li>
<ul>
<li><a href="/introduction">Introduction</a></li>
<li><a href="/requirements">Requirements</a></li>
<li><a href="/installation-setup">Installation and Setup</a></li>
</ul>
</li>
<li>
<h2>Basic Usage</h2>
<ul>
<li><a href="/basic-usage/your-first-menu">Your First Menu</a></li>
<li><a href="/basic-usage/working-with-items">Working With Items</a></li>
<li><a href="/basic-usage/adding-sub-menus">Adding Sub Menus</a></li>
</ul>
</li>
</ul>

Yup, that’s menu displayed on the docs of the menu package. Notice that there is a title before the second submenu. That piece of html can be generated by this code:

Menu::new()
->add(Menu::new()
->link('/introduction', 'Introduction')
->link('/requirements', 'Requirements')
->link('/installation-setup', 'Installation and Setup')
)
->add(Menu::new()
->prepend('<h2>Basic Usage</h2>')
->prefixLinks('/basic-usage')
->link('/your-first-menu', 'Your First Menu')
->link('/working-with-items', 'Working With Items')
->link('/adding-sub-menus', 'Adding Sub Menus')
);

If you want an item to be active, just call setActive on it

$menu = Menu::new()
->add(Link::to('/', 'Home'))
->add(Link::to('/about', 'About')->setActive());

Manually setting items to active will become very tiresome very soon. In most cases is probably better to let the package handle activating items automatically

$menu = Menu::new()
->add(Link::to('/', 'Home'))
->add(Link::to('/about', 'About')->setActive());
->setActiveFromRequest();

Instead of adding link objects you can also use some convenience methods to add items to a menu:

Menu::new()
->url('/', 'Home')
->route('contact', 'Contact')
->action('AcmeController@detail', 'Acme');

There are a lot more nice things included in the package such as attribute manipulation, conditionally prepending and appending content and support for macros. Learn it all on the documentation site.

Under the hood

Let’s take a quick look on how all this is implemented. Under the hood there are three packages:

When browsing the code you’ll see usages of scalar type hints, return types, anonymous classes, the null coalescing operator, typed arrays and higher order functions. Modern PHP is awesome, don’t let anybody tell you otherwise.

In closing

If you want to learn more about our menu package, head over to the documentation site. We’ve provided a lot of examples to get you started.

All three underlying packages were designed and coded up by my colleague Sebastian. I think he did an amazing job. If you like his work take the time to thank him on Twitter.

As a company Spatie uses a lot of open source software. That’s one of the reasons we try to give as much back as possible. Take a look at our other Laravel, PHP and JavaScript packages to see if we made something useful for you.