Header burger menu
A burger menu with a left side panel that can hold navigation and other widgets on mobile devices.
The burger menu is a left side panel that can hold the main navigation on small screens.
Panel control
The burger menu is a complicated component, to make it accessible it's not enough to simply visually display it and make it slide, we need to make sure the whole thing is wired correctly and some user interactions should be manipulated to effectively lock focus in and out of the panel.
Here are the details you should pay attention to:
The first toggle button:
- Opens the panel that contains the burger menu
- Requires an internationalized
aria-label
that tells the user what's the purpose of the button, in this case "Open the menu panel" or something equivalent - Has two important attributes:
aria-controls="{the-panel-id}"
that will associate the toggle with the panelaria-expanded="true|false"
this informs the state of the panel: opened or closed
The second toggle button inside of the panel:
- Is for closing the panel and should be the first element of the panel container to receive focus when the panel is opened
- Has the same ARIA attributes as the first button, and the
aria-expanded
status of both buttons should be in sync - Also requires an
aria-label
that says "Close the menu panel" or similar - Receives focus when the panel is opened
The panel container:
- Should have an
id
that is passed to the toggle'saria-controls
attribute - When collapsed must have the
hidden
attribute, this effectively removes it from the tab order and from the accessibility tree
To open the panel:
- Set both
aria-expanded
of the toggle buttons to true - Remove the
hidden
attribute from the panel - Set the focus on the first element of the panel (which is the close button)
- Block users from scrolling the page by adding
overflow: hidden;
CSS rule to the body element
To hide the panel:
- Set
aria-expanded
of both toggles to false - Add
hidden
attribute to the panel - Set the focus back on the first toggle (the burger button) so users can continue navigating the web site
- Remove the
overflow: hidden
CSS rule from the body to enable scrolling again - Users must be able to close the panel by pressing ESC on the keyboard
- You should close the panel when users tab away from it (when any element that is not inside of the panel receives focus)
<header class="flix-header flix-header--unfixed">
<div class="flix-header__inner">
<div class="flix-header-brand flix-header-brand--square">
<a class="flix-header-brand__link" href="/">
<img class="flix-header-brand__img" width="36" height="36" src="/img/logos/svg/honeycomb-white.svg" alt="Honeycomb Logo"/>
</a>
</div>
<div class="flix-header-burger-menu">
<button type="button" aria-label="Open main site navigation" class="flix-header-burger-menu__toggle flix-btn flix-btn--link flix-btn--square flix-btn--md" aria-controls="menu-panel" aria-expanded="false"></button>
<div id="menu-panel" class="flix-header-burger-menu__panel" hidden="">
<button type="button" aria-label="Close main site navigation" class="flix-header-burger-menu__toggle flix-btn flix-btn--link flix-btn--square flix-btn--md" aria-controls="menu-panel" aria-expanded="false"></button>
The burger menu content.
</div>
<div class="flix-header-burger-menu__overlay flix-overlay"></div>
</div>
</div>
</header>
Burger menu navigation
The burger menu navigation markup is identical to the header navigation, only changing the class names. Even the sub-menu control. You may even use the same component for both, making sure to adapt the class
names and id
s according to the position you're using it.
If you have the same navigation on the hamburger menu and on the header navigation, you should provide the same aria-label
for both nav
landmarks, this enables screen readers to only index one of them, reducing the clutter.
Also, make sure to provide different id
s for the sub-menus, since you are not allowed to have multiple elements with the same id
on a page.
The burger menu navigation class names are: flix-header-burger-menu
then add the element class names just the same as in the header navigation.
<header class="flix-header flix-header--unfixed">
<div class="flix-header__inner">
<div class="flix-header-brand flix-header-brand--square">
<a class="flix-header-brand__link" href="/">
<img class="flix-header-brand__img" width="36" height="36" src="/img/logos/svg/honeycomb-white.svg" alt="Honeycomb Logo"/>
</a>
</div>
<div class="flix-header-burger-menu">
<button type="button" aria-label="Open main site navigation" class="flix-header-burger-menu__toggle flix-btn flix-btn--link flix-btn--square flix-btn--md" aria-controls="menu-panel" aria-expanded="false"></button>
<div id="menu-panel" class="flix-header-burger-menu__panel" hidden="">
<button type="button" aria-label="Close main site navigation" class="flix-header-burger-menu__toggle flix-btn flix-btn--link flix-btn--square flix-btn--md" aria-controls="menu-panel" aria-expanded="false"></button>
<nav class="flix-header-burger-menu__nav" aria-label="Main">
<ul class="flix-header-burger-menu__list">
<li class="flix-header-burger-menu__item">
<a class="flix-header-burger-menu__link" aria-current="page" href="/">
<i class="flix-icon flix-icon-home-solid" aria-hidden="true"></i>
<span class="flix-header-burger-menu__text">My bookings</span>
</a>
</li>
<li class="flix-header-burger-menu__item">
<button type="button" class="flix-header-burger-menu__link" data-dropdown="flix-burger-subnav">
<i class="flix-icon flix-icon-location-solid" aria-hidden="true"></i>
<span class="flix-header-burger-menu__text">Plan trip</span>
</button>
<ul id="flix-burger-subnav" class="flix-header-burger-menu-subnav" hidden="">
<li class="flix-header-burger-menu-subnav__item">
<a class="flix-header-burger-menu-subnav__link" aria-current="page" href="/">
<i class="flix-icon flix-icon-trip-solid" aria-hidden="true"></i>
<span class="flix-header-burger-menu__text">Route Network</span>
</a>
</li>
<li class="flix-header-burger-menu-subnav__item">
<a class="flix-header-burger-menu-subnav__link" href="/">
<i class="flix-icon flix-icon-pin" aria-hidden="true"></i>
<span class="flix-header-burger-menu__text">Coach destination</span>
</a>
</li>
<li class="flix-header-burger-menu-subnav__item">
<a class="flix-header-burger-menu-subnav__link" href="/">
<span class="flix-header-burger-menu__text">Night buses</span>
</a>
</li>
</ul>
</li>
<li class="flix-header-burger-menu__item">
<a class="flix-header-burger-menu__link" href="/">
<i class="flix-icon flix-icon-real-time" aria-hidden="true"></i>
<span class="flix-header-burger-menu__text">Real-time</span>
</a>
</li>
<li class="flix-header-burger-menu__item">
<a class="flix-header-burger-menu__link" href="/">
<span class="flix-header-burger-menu__text">About Us</span>
</a>
</li>
</ul>
</nav>
</div>
<div class="flix-header-burger-menu__overlay flix-overlay"></div>
</div>
</div>
</header>
Burger menu widgets
Just like the header widgets area, the burger menu widgets is a container for whatever component you like, it is shown bellow the burger menu.
By default, the widgets container has no styles applied to it, if you wish to apply paddings equal to the menu, add the --has-container
modifier to the widgets element.
The example bellow shows the language switcher toggle (please check the language switcher component page for working examples):
<header class="flix-header flix-header--unfixed">
<div class="flix-header__inner">
<div class="flix-header-brand flix-header-brand--square">
<a class="flix-header-brand__link" href="/">
<img class="flix-header-brand__img" width="36" height="36" src="/img/logos/svg/honeycomb-white.svg" alt="Honeycomb Logo"/>
</a>
</div>
<div class="flix-header-burger-menu">
<button type="button" aria-label="Open main site navigation" class="flix-header-burger-menu__toggle flix-btn flix-btn--link flix-btn--square flix-btn--md" aria-controls="menu-panel" aria-expanded="false"></button>
<div id="menu-panel" class="flix-header-burger-menu__panel">
<button type="button" aria-label="Close main site navigation" class="flix-header-burger-menu__toggle flix-btn flix-btn--link flix-btn--square flix-btn--md" aria-controls="menu-panel" aria-expanded="false"></button>
<div class="flix-header-burger-menu__widgets flix-header-burger-menu__widgets--has-container">
<div class="flix-language-switcher">
<button type="button" class="flix-language-switcher__toggle">
<img class="flix-language-switcher__flag" src="https://honeycomb-assets.hive.flixbus.com/honeycomb-flags-static/2.0.0/svg/de.svg" alt="Deutschland"/>
Deutsch
</button>
</div>
</div>
</div>
<div class="flix-header-burger-menu__overlay flix-overlay"></div>
</div>
</div>
</header>