Skip to content
Contact me

All building blocks

Sandbox

The dropdown menu

The trap I flag most often in audits of a navigation bar is a role="menu", which makes it pass for the menu of a desktop app. With the popover attribute, your list closes with Escape and with a click elsewhere, and the browser exposes the expanded state of the button.

Built with
popover
Browsers
Chrome 125+, Firefox 147+, Safari 26+
JavaScript
None

Demo

Anatomy

  1. nav The navigation, named with aria-label.
  2. button popovertarget The button that expands the list.
  3. ul popover The expanded list, above the page and anchored under the button.
  4. a A link in the list.

HTML code

HTML
<nav aria-label="Main navigation">
  <ul>
    <li>
      <!-- Trigger: opens and closes the submenu -->
      <button type="button" popovertarget="account-menu">My account</button>
      <!-- Submenu: plain links in a popover, with no menu role -->
      <ul id="account-menu" popover>
        <li><a href="/account/profile">My profile</a></li>
        <li><a href="/account/orders">My orders</a></li>
        <li><a href="/account/settings">Settings</a></li>
        <li><a href="/sign-out">Sign out</a></li>
      </ul>
    </li>
    <li><a href="/help">Help</a></li>
  </ul>
</nav>
CSS
/* The list anchors under its button, instead of the center of the screen.
   One anchor name per button: with a shared name,
   every list would open under the last button */
[popovertarget="account-menu"] {
  anchor-name: --account-button;
}

#account-menu {
  position-anchor: --account-button;
  inset: auto;
  top: anchor(bottom);
  left: anchor(left);
  margin: 6px 0 0;
}

Usage

Use it for

  • Grouping the pages of a section in the main navigation.
  • A short list of links, readable at a glance.

Avoid it for

  • role="menu" and role="menuitem" on a site navigation. They promise the arrow keys of an application menu, like File or Edit.
  • A list that only opens on hover.
  • A "My account" link that also opens the list: an element is a link or a button, never both.

Accessibility

ARIA roles and attributes

A single ARIA attribute, aria-label on the navigation. The button state comes from popovertarget, with no aria-expanded.

AttributeElementDescription
aria-label="Main navigation"navNames this navigation landmark: the screen reader tells it apart from the other navigations on the page.
popovertarget="account-menu"buttonTies the button to the list id="account-menu". The screen reader gets "My account, collapsed, button", then "expanded" when it opens.
popoverulWhen closed, the list leaves the accessibility tree. When open, the screen reader gets an ordinary list, placed right after the button in the code: it is read and browsed in order.

Keyboard navigation

KeyAction
TabReaches the My account button, then the links if the list is open
Enter or SpaceOpens or closes the list
EscapeCloses the list. If focus was on a link, it goes back to the button
Tab after the last linkMoves to the Help link. The list stays open until Escape or the next click elsewhere

Tab order

  1. The "My account" button.
  2. "My profile", if the list is open.
  3. "My orders".
  4. "Settings".
  5. "Sign out".
  6. The "Help" link. With the list closed, Tab goes straight there from the button.

With a screen reader

Example in Chrome with VoiceOver in English. The wording changes from one screen reader to another.

ActionAnnouncement
Tab to the button"My account, collapsed, button"
Enter"expanded"
Tab"link, My profile"

Related RGAA criteria

The RGAA is the French accessibility standard. Its 106 criteria test WCAG 2.1 level AA.

Criterion 10.7: On each web page, for each element that receives focus, is the focus visible?
Focus stays visible on the button and on each link.
Criterion 12.8: On each web page, is the tab order consistent?
The tab order follows the code order: the button, its links, then the rest.
Criterion 12.11: On each web page, can additional content that appears on hover, on focus or when a user interface component is activated be reached with the keyboard, where needed?
The links that appear when the button is activated can be reached with the keyboard.

Other references

Beyond the APG

New featureWhat it addsBrowsersIn the demo
popover and popovertargetOpen the list, close it with Escape or a click elsewhere, and give the button its state, collapsed or expanded.Chrome 116+, Firefox 125+, Safari 17+Yes
CSS anchor positioning (anchor-name, position-anchor)Places the list under its button, with no JavaScript calculation.Chrome 125+, Firefox 147+, Safari 26+Yes
interestforOpens the list on hover and on focus, with a delay, with no script.Chrome 149+, Edge 149+No

Variations

Link and button side by side

The "My account" link leads to the account home page, and a button right next to it expands the list. Each keeps a single role.

Code
<li>
  <a href="/account">My account</a>
  <button
    type="button"
    popovertarget="account-menu"
    aria-label="Account pages">▾</button>
  <ul id="account-menu" popover>…</ul>
</li>

With details

details and summary instead of popover. It works in older browsers, but Escape does not close it, and the list stays open when you click elsewhere.

Code
<details>
  <summary>My account</summary>
  <ul>…</ul>
</details>