Status: This is not ready for detailed review. It is an in-progress, unapproved editor’s draft.
If the user should be able to access pages deep in the website’s structure, fly-out menus are frequently used to archive the desired effect. Such fly-out menus are often called dropdown menus.
As interactive components, fly-out menus need to be developed with accessibility in mind to make sure that they are operable using the keyboard as well. Hiding menu items not displayed from keyboards and assistive technologies makes sure that the menu can be easily navigated. For people with reduced dexterity it is also important that submenus don’t snap back immediately when the mouse leaves the clickable area.
Usually the first-level menu items are links to individual pages whether they have a submenu or not. The submenu should then be duplicated as a secondary navigation on the linked web page to make sure that those pages are quickly reachable from there. Submenus are individual lists (
<ol>), nested in the parent’s list item (
Items containing a submenu should be marked in a way that is obvious. In the following example, the SpaceBears menu item has a submenu:
For mouse users, hiding the submenu until the mouse hovers over the first-level menu item is quite easy, but has the disadvantage that the menu immediately closes once the mouse leaves the list item (and the containing submenu).
Improve mouse support
Improve keyboard support
To improve Keyboard support, the decision has to be made if the top-level menu item should serve as a toggle for the menu for all users or be a link itself. Don’t just open the submenu as soon as the focus enters the parent menu item, as that would mean a keyboard user tediously needs to step through all the submenu links to get to the next top-level item.
Toggle submenu using the top-level menu item
The activation of the top-level menu item won’t link to the page in its
href attribute but instead show the sub menu. A script stops the browser from following the link to the page. If the focus leaves the submenu (for example by using the tab key on the last submenu item), the submenu needs to close.
The following code iterates through all menu items and adds click event to the first (top-level) link in each menu item. The click event fires regardless of input method as soon as the link gets activated. If the submenu is closed when the link is activated, the script opens the submenu, and vice versa.
Toggle submenu using a special “show submenu” button
If the top-level menu item should stay a link to a page, adding a separate button that toggles the submenu is the most reliable way to address the issue.
In the following code, a button is attached to every menu item link with a submenu. The click event listener is applied to this button and toggles the menu. The invisible button text is changed from show to hide submenu according to the state of the submenu.
Improve screen reader support using WAI-ARIA
Currently, screen reader users are unable to tell if an item has a submenu or not and if it is opened. WAI-ARIA helps to convey this information by adding the following two attributes to the menu’s HTML:
aria-haspopup="true"is used so screen readers are able to announce that the link has a submenu.
aria-expandedis initially set to
falsebut changed to
truewhen the submenu opens which forces screen readers to announce that this menu item is now expanded.
Web application menus
There are some WAI-ARIA roles that are helping assistive technology to interpret menus like the ones found in desktop software. When using the menu WAI-ARIA attributes, the keyboard interaction should be similar to desktop software as well: the tab key is used to iterate through the top-level items only, the up and down arrows are used to navigate the sub menus. This keyboard behavior doesn’t come with the WAI-ARIA attributes, but needs to be added using scripting.
In addition to the
aria-haspopup attributes, the following roles are used in the example:
aria-menubar: Represents a usually horizontal menu bar.
aria-menu: Represents a set of links or commands in a menu bar, it is used for the fly-out menus.
aria-menuitem: Represents an individual menu item.
The markup has no links, it is a bare nested list with some WAI-ARIA roles. As we will add keyboard and mouse interaction on our own, this is enough.
First, we collect all top-level menu items in a variable (
appsMenuItems) as well as all submenu items (
subMenuItems). An object is defined with the key codes of the keys that need to be handled. This makes the code much more readable. Two variables keep track of the focus in top-level items (
currentIndex) and in submenus (
To make the menu work for keyboard users, a
tabindex attribute with the value
-1 is added to the menu items. This enables scripts to set the focus on the element. The first menu item (“File” in this example) is assigned a
tabindex value of
0 which adds it to the tab order and lets the user access the menu. The
currentIndex variable is initialized as soon as this first item gets focus.
All top-level menu items close open submenus when they receive focus and reset the
subIndex variable. When individual items are clicked, the visibility of the submenu is toggled by changing the
aria-expanded value. If a key is pressed, the appropriate action is carried out.
|tab ⇥||Select the next top-level menu item|
|shift ⇧ + tab ⇥||Select the previous top-level menu item|
|return/enter ↵||Open the submenu, select first submenu item.|
|up ↑||Open the submenu, select last submenu item.|
|esc||Leave the menu|
Submenu items do behave differently when interacting with them on the keyboard, see the following table for details:
|tab ⇥||Close the submenu, select the next top-level menu item|
|shift ⇧ + tab ⇥||Close the submenu, select the previous top-level menu item|
|return/enter ↵||Carry out function of this item. (In this example: bring up a dialog box with the text of the chosen menu item.)|
|down ↓||Select next submenu item|
|up ↑||Select previous submenu item|
|esc||Close the submenu, select the current top-level menu item|