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:
- 2.1.1 Keyboard — all functionality must be available from a keyboard
- 4.1.2 Name, Role, Value — all UI components must expose correct role, name, and state
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 — NOrole="menu"orrole="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
Navigation Mega Menu
ARIA Menu Roles vs. Disclosure Pattern for Mega Navigation
<!-- 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><!-- 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>What’s wrong with role="menu" on site navigation?
role="menubar"androle="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 withrole="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:
| Version | Announcement |
|---|---|
| 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