Skip to content
easeweb
Search topics

Dropdown parent links that open the submenu, not the page

One link both goes to a section page and opens its submenu, so a script decides what Enter does, and nothing says whether the list or the page will open.

WCAG 2.2
SC 2.1.1ASC 4.1.2A
Required by
Section 508 · EN 301 549 (EU)
Broken event.preventDefault();
The accessibility problem illustrated: No vision:Will Enter open the list, or the page?
01

The problem

Keyboard users can't rely on a menu link to take them to its page, and screen reader users can't tell whether Enter will open a list or leave the page.

02

Try it

Using only the keyboard, go to the Products page, then to Lamps.

  • Broken 1: press Enter on Products. The list opens, but the panel still says only "Products, link". Press Enter again and you leave for the Products page, with nothing to say you would.

  • Broken 2: Enter on Products opens and closes the list, and never reaches the Products page. Click Products with the mouse, and you get there at once.

  • Apply a fix. Enter on a link always goes to its page, and the list opens from a button that says whether it is open.

Broken Can you fix this?

Screen reader says:

(Tab to the menu)

A recreated demo. The broken version is intentionally inaccessible.

03

The fix

Give the page a link and the list a button of its own.

Before

The first press opens the list, the second follows the link

<nav aria-label="Main">  <ul class="menu">    <li>      <a href="/">Home</a>    </li>    <li class="has-sub">      <a href="/products">Products</a>      <ul>        <li>          <a href="/products/lamps">Lamps</a>        </li>        <li>          <a href="/products/chairs">Chairs</a>        </li>        <li>          <a href="/products/rugs">Rugs</a>        </li>      </ul>    </li>    <li>      <a href="/about">About</a>    </li>  </ul></nav>
What is wrong2 points

A mouse opens the list on hover, so its click always follows the link. Enter on a link fires the same click, and that is where it goes wrong.

  • The first Enter on Products is cancelled, and the list opens in its place.
  • Products is announced as "Products, link" before and after, so nothing says the list opened, or that the next Enter will leave the page.
After

The link, and a button beside it

<nav aria-label="Main">  <ul class="menu">    <li>      <a href="/">Home</a>    </li>    <li class="has-sub">      <a href="/products">Products</a>      <button type="button" aria-expanded="false" aria-controls="sub-products" aria-label="Products pages">▾</button>      <ul id="sub-products" tabindex="-1" hidden>        <li>          <a href="/products/lamps">Lamps</a>        </li>        <li>          <a href="/products/chairs">Chairs</a>        </li>        <li>          <a href="/products/rugs">Rugs</a>        </li>      </ul>    </li>    <li>      <a href="/about">About</a>    </li>  </ul></nav>
How it is fixed6 steps
  1. Leave Products as a plain link with no handler, so Enter, a click and a tap all go to the Products page, the first time.
  2. Put a native button straight after it, drawn as the chevron, which opens and closes the list with Enter, Space or a click.
  3. Name the button "Products pages", so a screen reader and voice control tell it apart from the link, and keep it at least 24 by 24 pixels.
  4. Give it aria-expanded, kept in step with hidden, so it is announced as "Products pages, button, collapsed", then "expanded", and tie it to the list with aria-controls.
  5. Close the list on Escape and put focus back on the button, and close it when focus leaves the item, without moving focus.
  6. Put tabindex="-1" on the list, so a click inside it keeps focus within the item and doesn't count as leaving.

This fixes both Befores and passes 2.1.1 and 4.1.2: each control does one job and says which. It is the shape of the W3C's disclosure navigation example with top-level links, and of the WordPress Navigation block's submenus when they open on hover with their arrow shown.

Why this fix: Use native HTML first

Easily confused
04

Design ideas

One item can lead to its page and open its list.

Four ways to draw Products. Put the mouse aside and Tab through each: Enter on a word goes to its page, and Enter on a chevron or + opens the list. Three keep both within reach of the keyboard; in the last, only a pointer opens the list.

In the design file

  • Decide whether a press on the word Products goes to its page or opens its list, never both.
  • If the word goes to the page, draw the chevron or + as a target of its own, set apart by a line or a gap.
  • If the word opens the list, put the Products page in the list, first and easy to spot.
  • Name the chevron in the design file, such as “Products pages”, so it differs from the link beside it.
  • Draw the open state too, with the chevron turned over or the + turned to −.

Passes

  • One pill, split by a line Products and its chevron share one outlined pill, split by a 1px line, so the item reads as one thing with two ends: the word goes to the page, and the chevron opens the list and turns over. Each half fills on its own hover and takes its own focus ring; the ink is #1a1a1a on white, 17.40:1.

    Rule of thumb: Use native HTML first

  • A panel that leads with the overview Products only opens the panel, and the page it used to open becomes the panel’s first and largest link, a tinted card reading “All products”, #1a1a1a on #f5f2ec at 15.58:1. The header keeps one Tab stop, and the overview is one press further, where nobody misses it.

    Rule of thumb: Use native HTML first

  • Phone menu: the row and its own + In the phone menu, the Products row splits in two: the words go to the page, and a square + at the right end, set apart by a line, opens Lamps, Chairs and Rugs beneath it and turns to −. The first tap on the words always leaves, so nobody has to guess.

    Rule of thumb: Use native HTML first

Fails

05

Verify the fix

5 checks, no mouse.

Test with: Keyboard, Screen reader, Touch, Zoom

0 of 5 checked

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared header or menu component changes.

How screen readers handle aria-expanded

Limits

This guide covers a top-level item that is a link and opens its submenu as well. A submenu that opens only on hover, with no script and no button, and a button that never says whether its list is open, are covered in hover-only dropdowns, or ones that never say they are open. Application menus of commands follow the ARIA menu pattern instead. The scripts are minimal sketches without animation, hover opening or nested levels. Test the complete journey, including your narrow-screen menu, with your target assistive technology.

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

EaseWeb service

Fixed it? Keep it from coming back.

I turn guides like this one into rules your coding agents follow and checks your CI runs. Then I retest by hand with a keyboard and screen readers, periodically.

See the service