The navigation menu is a crucial element of any website, guiding users through content, enhancing their experience, and playing a vital role in the site's overall usability and success.
Creating a menu that's accessible, responsive, and easy to navigate is a non-trivial task, no matter how simple or complex your navigation is. However, people usually underestimate the efforts required to create a navigation menu that provides a good user experience, and that it can take several iterations to do it right.
But if you're using Drupal, there's a shortcut to getting it right.
Requirements for a great navigation menu
Many aspects of a modern navigation menu are often not accounted for. Navigation for a CMS should have the following qualities:
- It is robust. Your navigation should work equally well for two, three, or ten items; you usually don't know how many menu items (or sub-menu items) there will be. It should also support menu items with any number of characters or words, especially in cases where a menu item doesn't fit on a single line.
- It is accessible. In 2024, your navigation menu must meet at least WCAG 2.1 AA standards. Fully keyboard navigable, including opening and closing sub-menus. The submenus should open on hover, click, and tap, covering every device type. Submenus should close if you press the "escape" key or click anywhere outside the submenu. Navigation on smaller devices should also be accessible through the use of the keyboard.
- It is smart about smaller screen space. Submenus shouldn't overflow the viewport height. If this happens, it should provide a scrolling mechanism or some solution for navigating to the sub-menu items that aren't visible. Good navigation systems should render differently on smaller devices to accommodate the limited space.
- It traps the focus. If you open the navigation menu through the keyboard and press the tab key to navigate through the sub-items, the focus should stay inside the menu until it's closed and not jump to other elements on the page.
Creating a robust menu system is not easy and can consume endless hours to get right. Lucky for you, if you are using Drupal, all these aspects have already been taken care of in the Olivero theme, as described in this Smashing Magazine article:
With version 9.4, Drupal has a brand new default theme called Olivero. Being the default, we knew its navigation system would be used by hundreds of millions (if not billions) of users throughout its lifetime. And of all the things that we are proud of with Drupal’s new theme, the navigation system tops the list. An enormous amount of testing, bug fixes, and care went into it.
When we had to think about developing the navigation system for a government platform used on dozens of sites and by millions of users with different needs and devices, we looked toward Olivero for guidance. After all, we helped design, research, and develop Olivero, so we might as well take advantage of it.
Would it be possible to somehow reuse the Olivero navigation menu on our custom theme? The answer was yes, it was possible, and surprisingly, it was not very complicated. As long as you are using a standard Drupal menu.
How to reuse Olivero's menu
We started by looking at the similarities and differences between the navigation menu that was being designed for the state of Iowa and the Olivero menu, then proposed a few cosmetic changes to the designers to make the implementation simpler.
For comparison, here is the default Olivero menu and the final version.
The biggest difference in Iowa's version is a "mega menu," while Olivero's version lists sub-items in a single column, but we left some design elements in place, like the small caret above the submenu as well as the border at the top. All of this can be overridden with CSS, and you can implement virtually any design you like.
To replicate the Olivero menu in our custom theme, we looked at the JS, CSS, and template files in Olivero with the goal of modifying them as little as possible. Minimal changes meant we could easily bring future bug fixes or improvements from Olivero to our custom theme.
The first step was to copy the Olivero menu template to our custom theme. Olivero's main menu template can be found at core/themes/olivero/templates/navigation/menu--primary-menu.html.twig
, which we renamed to menu--main.html.twig
. The content of the file is mostly the same, except for some adjustments to account for the two-column mega menu we were implementing.
Then we moved over the Olivero menu Post CSS files to our project and converted them to SASS. Since we had to identify from the olivero/css/components/navigation
directory which files we needed to move over and which files we could ignore, this task wasn't so simple. We ended up modifying a lot of the CSS for our implementation.
Here's the list of files from Olivero compared to our custom theme directory.
Since we only cared about the main navigation, we ignored all the other files. We did have to replace variables that didn't exist in our custom theme, as well as adjust styling. Since the CSS files were not preserved unmodified, that is something that will need to be maintained from now on.
The most important task was identifying the JavaScript files interacting with the main navigation and finding a way to keep this part unmodified as a dependency.
To achieve this, we defined a custom library on our theme called olivero-navigation
which contains the necessary original files.
We also included navigation-util.js
as a global dependency.
The final challenge
After some adjustments, our custom project navigation started working just fine! But we had a final challenge. We needed to implement custom JavaScript interactions with the menu without modifying the ported JavaScript files.
For example, on mobile, when the search button is tapped, the mobile menu should be closed and vice versa. So, in a custom JavaScript file, we defined a MutationOberver that looks for changes on the aria-expanded attribute of the menu and reacts to it. We also found we could change the Olivero menu state from "open" to "close" by changing a few attributes.
If you are starting a Drupal project and need a robust navigation system, consider following this approach or building off the wonderful Olivero theme with starterkit.