Accessible navigation menus and mega menus

An accessible navigation menu is a list of links inside a labeled nav element, with each drop-down opened by a real button that reports whether it is expanded. It works from the keyboard as well as the mouse, and Escape closes an open drop-down. W3C's guidance and the ARIA Authoring Practices disclosure example build site menus from links and buttons, not from the ARIA menu roles; in our reading a mega menu is the same pattern with a bigger panel.

Published . Last reviewed .

A navigation menu is the set of links a site uses to get around itself. A mega menu is the same menu with a large drop-down panel, usually with many links grouped under headings. Both must work for people who never use a mouse, and the markup decides whether they do: a list lets a screen reader announce how many items a menu has, and a real button can be reached and operated from the keyboard where a clickable div cannot. W3C's menus tutorial counts menus among the critical parts of a web page that need particular attention.

Three faults to look for first: a submenu that opens only on hover, a parent item that is a bare div, and an open panel that cannot be closed from the keyboard. This guide covers site menus made of links; for neighboring patterns, see accessible modals, accordions and tabs and buttons versus links.

What the standards ask of a menu

No WCAG success criterion is written only for menus, but these apply to nearly every one. The plain-language readings are ours.

W3C's menus tutorial also relates menus to 2.4.1 Bypass Blocks, so a long menu needs a way past it: see our skip links guide.

Mark up the menu as a list of links in a labeled nav

W3C's menu structure page asks for four things:

  • A list. Menus should typically be lists, so assistive technology can announce how many items there are. An unordered list suits most site navigation.
  • A labeled nav. The nav element lets people reach the menu directly. Give each menu a short, descriptive label, so people can tell several apart, using a heading, aria-label or aria-labelledby. Our landmarks guide covers naming.
  • The current item marked. Put aria-current="page" on its link, and show it visually too.
  • The same order, wording and destination for visible items at every screen size.

Breadcrumbs have their own guide: breadcrumbs and navigation. Menus are one step in how to make a website accessible.

Site menus use disclosure buttons, not ARIA menu roles

The ARIA Authoring Practices Guide (APG) has an example for exactly this case: disclosure navigation. Each top-level button reveals a dropdown list of links for one section of the site. It does not use the WAI-ARIA menu role, because the example does not provide the complex functionality that assistive technologies expect in a widget with that role.

The roles menubar, menu and menuitem are for menus that work like desktop application menus. W3C's application menus page says such menus typically do not have links and rely on scripting, and that adding the roles does not by itself supply the menu's keyboard behavior. The APG's menubar pattern also lists a navigation menubar example, but its disclosure example says typical site navigation does not need all the keyboard interactions of the menu and menubar pattern.

Site navigation and application menus compared, from the APG example and W3C's application menus page
FeatureSite navigation (disclosure)Application menu (menubar)
HoldsLinks to pagesCommands, such as Undo and Paste
MarkupNav, lists, buttons with aria-expandedRoles menubar, menu, menuitem
Tab keyMoves among the buttons and into an open dropdown's linksOne tab stop; Tab leaves the menu

If your menu is a list of links to pages, use the left column. The menu roles promise a desktop-style widget that a script must then deliver, and a page of links does not need that. That is our reading of these sources. For when ARIA helps and when it gets in the way, see ARIA basics.

The markup for a drop-down

This sketch follows the structure of the APG pattern: a nav, nested lists, and buttons with aria-controls and aria-expanded. Using hidden to hide the panel is our choice; on each activation a script flips aria-expanded and hidden together.

<nav aria-label="Main">
  <ul>
    <li><a href="/" aria-current="page">Home</a></li>
    <li>
      <button type="button" aria-expanded="false" aria-controls="shop-links">Shop</button>
      <ul id="shop-links" hidden>
        <li><a href="/shop/kitchen/">Kitchen</a></li>
        <li><a href="/shop/garden/">Garden</a></li>
      </ul>
    </li>
  </ul>
</nav>
  • aria-controls names the list the button shows and hides.
  • The MDN page on hidden says hidden content is hidden from all presentations, screen readers included, and that a CSS display rule on the element overrides the attribute.
  • If you can, let the script add the buttons and the hidden attribute (our preference), so the links stay reachable when the script does not load. W3C's fly-out page makes a related point: a parent item that toggles its submenu can still link to a real page in case JavaScript is not loaded.

Open on activation, close with Escape

W3C's fly-out menus page says submenus should not open when someone Tabs through the menu, because keyboard users would have to step through every submenu item to reach the next top-level item. It offers two approaches. Make the parent the toggle when it only summarizes its submenu. Add a separate button beside the parent link when the parent must also go somewhere, and, where possible, put the parent's name in the button's label.

W3C's tutorial changes a hidden label between "show" and "hide" as the state changes. The APG example keeps one name on the button and lets aria-expanded carry the state. We prefer the APG form; that is a preference, not a requirement of either source.

Keys for a disclosure navigation menu, from the APG example
KeyWhat it does
Tab, Shift+TabMove among the top-level buttons and, if a dropdown is open, through its links.
Enter, SpaceToggle a disclosure button, or activate a link.
EscapeClose an open dropdown and put focus on its button.
Arrow keys, Home, End (optional)Move between the top-level buttons, and between the links of an open dropdown.

The APG example also closes an open dropdown when focus leaves the navigation, and says the optional keys are primarily for the benefit of keyboard users who are not running a screen reader. Make Tab, Enter, Space and Escape do everything.

Hover, focus and the pointer

Success criterion 1.4.13 Content on Hover or Focus (Level AA) covers content that appears on hover or keyboard focus, and its Understanding document lists sub-menus as examples. Such content must be dismissible without moving the pointer or focus (W3C's example is Esc), hoverable (the pointer can move onto it without it vanishing) and persistent (it stays until the trigger is removed or the user dismisses it).

W3C's fly-out page adds a closing delay, one second in its example, because it makes menus easier to use when mouse navigation is not precise. It also says people with reduced dexterity, such as tremors, often have trouble with fly-out menus, and recommends other ways to reach the submenu items, for example by repeating them on the parent item's page.

A submenu that opens only when someone activates a button is not triggered by hover or focus, so in our reading 1.4.13 does not strictly govern it, though the APG example says its Escape behavior is needed to meet 1.4.13 and we would keep it either way. For hover-triggered content, the Understanding page for 1.4.13 points to 2.1.1: it should also be triggerable by keyboard focus. A hover-only submenu has no keyboard route.

Mega menus

Neither W3C's menus tutorial nor the APG example mentions mega menus by name, so this section is our reading of them. A mega menu needs no different pattern: a disclosure button and a panel with more in it. Three habits matter most:

  • Keep it closed until asked. W3C's reason for not opening submenus on Tab applies even more to a big panel.
  • Group links in lists and name each one. Put each group of related links in its own ul, extending W3C's advice to mark menus up as lists. Give every link text that stands on its own, and give image-only promo links alt text: W3C's Understanding document for 2.4.4 lists failure F89, an image with no accessible name that is a link's only content. See accessible link text.
  • Keep it on screen. W3C's styling page says menus should not overlap themselves when text is enlarged or the page is zoomed.

On small screens the menu often collapses behind a button. In our reading that is the same pattern one level up: a named button, aria-expanded and the list it shows.

Style the states

W3C's menu styling page asks for the current item to be marked visually as well as in markup, hovered and focused items that change, enough white space such as padding for people with reduced dexterity, and no reliance on color alone. It also says contrast requirements apply to menus and their items. See focus indicators, use of color for links, color contrast and touch target size.

Common menu mistakes

Six common menu mistakes, why each matters and the fix
MistakeWhy it mattersFix
The submenu opens only on hoverA keyboard user cannot open it. In our reading this fails 2.1.1, and W3C lists pointer-only event handlers as failure F54.Add a button that toggles on click, Enter and Space.
The parent is a div or span with a click handlerIt is not focusable and has no button role.Use a button, placed beside the link if the item also goes to a page.
aria-expanded missing, or never updatedA screen reader cannot say whether the section is open (4.1.2).Set false and true on each toggle.
The panel closes the moment the pointer leavesPeople with an unsteady pointer lose it. For a panel that opens on hover, 1.4.13 asks that the pointer can move onto it.Keep it open over the parent and the panel, with a short closing delay.
Escape does nothingKeyboard users have no quick way out. The APG example ties its Escape behavior to 1.4.13.Close on Escape and return focus to the button.
Closed panels stay focusable, hidden only by moving them off screenIn our reading, focus lands on links nobody can see, which fails 2.4.7.Use hidden or display: none.

Test a menu in a few minutes

Run these on each template with a menu, not on every page:

  1. Tab from the top with the mouse set aside. Every item should show focus, and Tab alone should not open a submenu.
  2. Activate each parent with Enter, then Space. The panel should open.
  3. Tab through the open panel, then press Escape. It should close and focus should land on the button that opened it.
  4. Open a panel and Tab out of the navigation. The APG example closes it.
  5. If hover also opens the menu, hover the parent and move the pointer onto the panel. It should stay open. Press Escape without moving: it should close.
  6. Zoom in and narrow the window. The menu should not overlap itself. Then listen with a screen reader, as in how a screen reader reads a page, for the menu's label, each button's name and state, and the current page.

Check it yourself

Two free tools check what a machine can: whether links and buttons have names, and whether link text is vague.

  • The link text checker lists every link with the name a screen reader announces and flags links with no name, vague text, bare URLs and identical text that goes to different places, such as a mega menu full of "View all" links. It reads the HTML your server sends, so for a menu that a script builds, paste the HTML from your browser's inspector.
  • The accessibility bookmarklet reads the page as your browser has rendered it, as it is when you click, so open the menu first. It reports links and buttons with no accessible name and the contrast of the text it can measure.

Neither presses keys, and the bookmarklet's own limits say it cannot tell whether a page works with a keyboard, so use the test above. The free scan (Scan my site for free) reads the HTML your server sends and flags links and buttons with no accessible name, positive tabindex values and aria-hidden on a focusable element. For the full routine, see the keyboard accessibility test.

Keep it checked

GotAlt checks the pages you monitor every week, compares the alt text of up to six images per page with the image itself, runs its rule checks, opens monitored pages in a browser for contrast and other checks that need a rendered page (see what we check), and reports what changed. Plans are from $69 a month. Audit my whole site from $69/mo.

Navigation menu questions

What makes a dropdown menu accessible?

Its links sit in a list inside a labeled nav, each drop-down is opened by a real button that reports aria-expanded, everything works from the keyboard alone, and Escape closes an open panel and returns focus to its button. Focus is always visible, the current page is marked with aria-current, and every link has a name that makes sense on its own.

Should a dropdown menu open on hover or on click?

Open it on activation: a click, Enter or Space on a button. W3C says submenus should not open when people Tab through a menu. If hover also opens it, WCAG 1.4.13 asks that the content can be dismissed, that the pointer can move onto it, and that it stays until the trigger is removed or the user dismisses it. Hover alone leaves keyboard users out.

Should a navigation menu use role="menu"?

Usually not. The ARIA menu roles are for menus that behave like desktop application menus, which W3C says typically do not have links. The APG's disclosure navigation example does not use the menu role for site navigation, because the example does not provide the complex functionality that assistive technologies expect from a widget with that role. Use a nav, a list of links and disclosure buttons instead.

Which keys should work in a dropdown menu?

Tab and Shift+Tab move through the top-level buttons and the links of an open dropdown. Enter and Space toggle a disclosure button or follow a link. Escape closes an open dropdown and returns focus to its button. The APG example also offers arrow keys, Home and End as optional extras for moving among the buttons and links.

What is a mega menu, and does it need special markup?

A mega menu is a large drop-down panel, often with many links under group headings. It needs no special pattern. Use the same disclosure button and list markup as a small drop-down, group links in lists, keep the panel closed until activated, and make every link's name clear on its own. That is our reading of the W3C and APG guidance.

How do I mark the current page in a navigation menu?

Add aria-current="page" to the link for the page being shown, as W3C's menu structure page and the APG example do, and style it so the difference is visible without relying on color alone. W3C also describes replacing the link with a span that carries visually hidden text naming the current page. Either way, mark it in the markup and visually.

How do I make a hamburger menu accessible?

Treat it as a disclosure button: give it a clear name such as Menu, set aria-expanded to false and true as the list opens and closes, and make sure the links inside are reachable with the keyboard. W3C asks that visible items keep the same order, wording and destination at every screen size. The button advice is our reading of the APG pattern.

Run the automated part on your own pages

The free scan runs 16 rule-based checks on up to 3 pages of your site, including links and buttons with no accessible name. It cannot press keys or open a menu, so use the test above for the rest. No signup.

Scan my site for free