Skip to Content
Component ExamplesMega Menus

Overview

Mega menus are large dropdown panels in site navigation that contain multiple groups of links, often organized by category. A common mistake is using role="menu" and role="menuitem" for these panels. The ARIA menu pattern is designed for application-style menus (like a text editor’s File menu), not for website navigation. When screen readers encounter role="menu", they enter a special interaction mode that swallows Tab, expects Arrow key navigation, and breaks the normal browsing experience. The correct pattern for mega menus is the disclosure pattern: a <button> with aria-expanded that toggles a panel of plain links.

WCAG Criteria:

Key requirements:

  • Use <nav aria-label="Main"> as the landmark wrapper
  • Use <button aria-expanded="false/true"> as the disclosure trigger for each category — never a link
  • The dropdown panel is a plain <div> containing <ul> with <a> links — NO role="menu" or role="menuitem"
  • Tab moves through all focusable elements in the open panel naturally
  • Escape closes the open panel and returns focus to its trigger button
  • Never use role="menu" for site navigation — it changes screen reader interaction mode

ARIA Menu Roles vs. Disclosure Pattern for Mega Navigation

Inaccessible
<!-- role="menu" on site nav — JAWS/NVDA enter application mode --> <nav> <ul role="menubar"> <li role="none"> <a role="menuitem" href="#" aria-haspopup="true" aria-expanded="false">Products</a> <div role="menu"> <a role="menuitem" href="/analytics">Analytics</a> <a role="menuitem" href="/automation">Automation</a> <a role="menuitem" href="/servers">Servers</a> <a role="menuitem" href="/storage">Storage</a> </div> </li> <li role="none"> <a role="menuitem" href="/pricing">Pricing</a> </li> <li role="none"> <a role="menuitem" href="/about">About</a> </li> </ul> </nav>
Live Preview
Accessible
<!-- Disclosure pattern — no menu roles, Tab works naturally --> <nav aria-label="Main"> <ul> <li> <button aria-expanded="false" onclick=" var expanded = this.getAttribute('aria-expanded') === 'true'; this.setAttribute('aria-expanded', String(!expanded)); var panel = document.getElementById('mega-panel'); if (!expanded) { panel.removeAttribute('hidden'); } else { panel.setAttribute('hidden', ''); } "> Products </button> <div id="mega-panel" hidden onkeydown=" if (event.key === 'Escape') { this.setAttribute('hidden', ''); var btn = this.previousElementSibling; btn.setAttribute('aria-expanded', 'false'); btn.focus(); } "> <p>Software</p> <ul> <li><a href="/analytics">Analytics</a></li> <li><a href="/automation">Automation</a></li> </ul> <p>Hardware</p> <ul> <li><a href="/servers">Servers</a></li> <li><a href="/storage">Storage</a></li> </ul> </div> </li> <li><a href="/pricing">Pricing</a></li> <li><a href="/about">About</a></li> </ul> </nav>
Live Preview

What’s wrong with role="menu" on site navigation?

  • role="menubar" and role="menu" cause JAWS and NVDA to enter a special interaction mode where Tab no longer moves between links — Arrow keys are expected instead
  • Users who do not know the application menu keyboard model (Arrow keys, Home/End, letter keys) will be trapped
  • <a> elements with role="menuitem" lose their link semantics — screen readers stop announcing “link” and say “menu item” instead
  • The trigger is an <a> link acting as a button, which confuses the semantic model — links navigate, buttons perform actions

What the screen reader announces:

VersionAnnouncement
Inaccessible (role=“menu”)“Products, menu item. Menu. Analytics, menu item. Automation, menu item.” — Tab may not work, Arrow keys expected
Accessible (disclosure)“Main, navigation. Products, collapsed, button” — on activate: “Products, expanded, button. Analytics, link. Automation, link.” — Tab moves naturally through links

Why the disclosure pattern is correct for mega menus:

  • <button aria-expanded> clearly communicates the toggle state
  • The panel contains plain <a> links that behave exactly as users expect — Tab moves through them
  • Escape closes the panel and returns focus to the trigger button, providing a clear exit
  • No special interaction mode is activated, so all normal keyboard behavior is preserved
  • The APG (ARIA Authoring Practices Guide) explicitly recommends the disclosure pattern for site navigation

Resources