Accessible Dropdown and Mega Menus for Online Stores

Updated ยท 7 min read

Short answer: An accessible store menu uses a real button with aria-expanded to open each submenu, works with Tab, Enter and Space, closes with Escape, and shows visible focus. Hover can be an extra, never the only way in. Test it with the Tab key and a screen reader.

Navigation is how shoppers find products. When a dropdown or mega menu opens only on mouse hover, cannot be reached with a keyboard, or is silent to a screen reader, some customers cannot browse your store at all. Menus are also one of the first places an automated or manual audit looks, because they appear on every page.

This guide covers the common menu failures, a simple pattern that fixes most of them, and how to test your own menu in about ten minutes. It is general information, not legal advice. For legal questions, talk to an attorney.

The four problems that show up most

Most inaccessible store menus fail in the same ways:

These map to several WCAG 2.1 success criteria, mainly 2.1.1 Keyboard, 2.4.7 Focus Visible and 4.1.2 Name, Role, Value. You can read the full text of the standard at w3.org.

Use the disclosure pattern, not the ARIA menu pattern

Many developers reach for role="menu" because the word "menu" sounds right. For website navigation, that is usually the wrong choice. The ARIA "menu" role is meant for application-style menus, like the ones in a desktop program, and it changes how screen readers and keyboards behave in ways site visitors do not expect.

For site navigation, the W3C's examples favor a simpler approach called a disclosure: a button that shows or hides a group of links. The button tells assistive technology whether the content is expanded or collapsed. The links inside stay ordinary links in a list.

The ingredients are:

  1. A real <button> for each item that has a submenu.
  2. aria-expanded="false" or "true" on that button, updated when it toggles.
  3. The submenu as a normal list of links inside a <nav>.
  4. Escape closes the open submenu and returns focus to its button.
  5. A visible focus indicator on every button and link.

A working example

Here is a minimal markup structure:

<nav aria-label="Main">
  <ul class="menu">
    <li><a href="/new">New arrivals</a></li>
    <li>
      <button type="button" aria-expanded="false" aria-controls="shoes-menu">
        Shoes
      </button>
      <ul id="shoes-menu" hidden>
        <li><a href="/shoes/boots">Boots</a></li>
        <li><a href="/shoes/sandals">Sandals</a></li>
        <li><a href="/shoes/sneakers">Sneakers</a></li>
      </ul>
    </li>
    <li><a href="/sale">Sale</a></li>
  </ul>
</nav>

And the script that drives it:

const buttons = document.querySelectorAll('nav button[aria-expanded]');

function closeMenu(button) {
  button.setAttribute('aria-expanded', 'false');
  document.getElementById(button.getAttribute('aria-controls')).hidden = true;
}

function openMenu(button) {
  // Close any other open submenu first
  buttons.forEach((b) => { if (b !== button) closeMenu(b); });
  button.setAttribute('aria-expanded', 'true');
  document.getElementById(button.getAttribute('aria-controls')).hidden = false;
}

buttons.forEach((button) => {
  button.addEventListener('click', () => {
    const isOpen = button.getAttribute('aria-expanded') === 'true';
    isOpen ? closeMenu(button) : openMenu(button);
  });
});

document.addEventListener('keydown', (event) => {
  if (event.key !== 'Escape') return;
  const open = document.querySelector('nav button[aria-expanded="true"]');
  if (open) {
    closeMenu(open);
    open.focus(); // return focus to the trigger
  }
});

Because the trigger is a native <button>, Enter and Space already activate it. You do not need to add custom key handling for those. A native button also exposes the correct role to screen readers without extra ARIA.

You can still open the menu on hover as a convenience for mouse users, but hover must not be the only way. If you add hover behavior, make sure the menu stays open while the pointer moves from the button into the submenu, and that it can be dismissed without moving the pointer.

Mega menus: keep the structure simple

A mega menu is the same pattern with more content. A few practical rules keep it manageable:

If your menu includes a sliding promotional banner, see accessible carousels and sliders.

Visible focus

When someone tabs through the menu, they need to see where they are. A common cause of failure is a stylesheet that removes the outline with outline: none and offers nothing in its place.

nav button:focus-visible,
nav a:focus-visible {
  outline: 3px solid #1a1a1a;
  outline-offset: 2px;
}

Pick a color with enough contrast against the background of the menu, including dark header bars. See 2.4.7 Focus Visible and the guide on checking color contrast.

The mobile menu toggle needs a name

The "hamburger" button is often an icon with no text. A screen reader announces it as just "button," or reads out a file name. Give it an accessible name and a state:

<button type="button" class="menu-toggle"
        aria-expanded="false" aria-controls="mobile-nav">
  <svg aria-hidden="true" focusable="false" width="24" height="24">...</svg>
  <span class="visually-hidden">Menu</span>
</button>

Alternatively, use aria-label="Menu" on the button. Either way, update aria-expanded when the panel opens and closes, and make sure Escape closes it.

If the mobile panel covers the page like a dialog, check that focus does not escape behind it and that a visible close button exists. If you use a true modal, move focus into it on open and return focus to the toggle on close. Cookie banners and chat widgets often compete with menus for focus, which is covered in cookie banners, popups and chat widgets.

How to test with the keyboard

You need only your keyboard and a few minutes. For a broader routine, see the 5-minute keyboard accessibility test.

  1. Load your home page and put your mouse aside.
  2. Press Tab until you reach the main navigation. Can you reach every top-level item?
  3. On an item with a submenu, press Enter or Space. Does the submenu open?
  4. Press Tab to move through the submenu links. Is the order logical?
  5. Press Escape. Does the submenu close and focus return to the button?
  6. Tab past the menu entirely. Can you leave without getting stuck?
  7. Watch the screen throughout. Is the focus indicator always visible?
  8. Repeat at a narrow browser width to test the mobile toggle.

Write down each failure with the page and step where it happened. A dated record of what you tested and fixed is useful later; see why a dated accessibility audit record matters.

How to test with a screen reader

Keyboard testing shows behavior; a screen reader shows what is announced. Free options include NVDA on Windows and VoiceOver on Mac and iPhone. Our screen reader testing basics guide covers setup.

What to listen for:

CheckWhat you should hear
Landing on a submenu buttonIts name, "button," and "collapsed"
After opening itThe state changes to "expanded"
Landing on the mobile toggleA meaningful name such as "Menu," not just "button"
Moving through submenu linksEach link's text, ideally in a list

Exact wording varies between screen readers and browsers, so focus on whether the name, role and state are all present rather than on matching a phrase.

Common mistakes to avoid

If your store runs on a hosted platform, the theme or app often controls the menu code. Check what you can change; see Wix and Squarespace, WordPress, or the Shopify lawsuit guide for platform-specific context. If you need help, read hiring someone to fix website accessibility.

Where this fits in the bigger picture

Fixing the menu is one part of a store-wide effort. Checkout, forms and product images matter just as much; see accessible checkout and the WCAG 2.1 AA checklist. If you received a demand letter, read what to do in the first two weeks and consider speaking with an attorney. When you are ready to see where your own menu stands, you can run a free scan.

Frequently asked questions

Can a menu still open on hover?

Yes, as long as hover is not the only way to open it. Keyboard, touch and screen reader users need a button they can activate. If you keep hover, make sure the submenu stays open while the pointer moves into it and can be dismissed without moving the pointer.

Should I use role="menu" for my store navigation?

Usually not. The ARIA menu role is designed for application-style menus and changes keyboard and screen reader behavior. For site navigation, a button with aria-expanded that shows a list of links is simpler and more predictable.

What should happen when a user presses Escape?

The open submenu should close and keyboard focus should return to the button that opened it. This keeps the user from losing their place. The same behavior should apply to the mobile menu panel.

Does the mobile menu icon need text?

It needs an accessible name, which can come from visually hidden text or an aria-label. An icon-only button with no name is announced as just "button," so a screen reader user cannot tell what it does. It should also report whether it is expanded or collapsed.

If I fix my menu, is my site protected from an ADA claim?

No single fix can promise that. A menu is one part of a site, and how courts treat website accessibility claims varies. Fixing known barriers and keeping dated records of your testing are sensible steps, and an attorney can advise on your specific situation.

Proof of Access provides technical accessibility assessments. We are not a law firm and nothing on this page is legal advice. If you have received a demand letter or a lawsuit, talk to an attorney.