01 — Foundation

Menus expose actions — not entire workflows

Dropdown menus work for secondary actions. They fail when they become hidden primary navigation.

Menus group related actions — row menus, profile menus, overflow controls. They must be keyboard operable, clearly labelled, and dismissible. For larger panels see Popovers; for site navigation see Navigation.

02 — Trigger

Triggers and labels

Users must know what the menu contains before it opens.

  • button with accessible name — “Actions for invoice 1042”, not icon-only without label
  • aria-expanded reflects open state; aria-controls points at the menu id
  • menu items are button or a — not div click handlers
<button type="button" aria-expanded="false" aria-controls="row-menu" aria-haspopup="menu">
    Actions
</button>
<ul id="row-menu" role="menu" hidden>
    <li role="none"><button type="button" role="menuitem">Duplicate</button></li>
</ul>

03 — Keyboard

Keyboard and dismissal

Arrow keys, Enter, Escape, and focus return are not optional.

  • arrow keys move between items; Escape closes and returns focus to the trigger
  • do not close on focus moving to the first item in a broken way
  • separate destructive items visually — see Destructive Actions
  • native popover or platform menu patterns where they meet requirements

04 — Review

Before you approve

A short checklist for menus in code review.

  • labelled trigger; semantic menu items; expanded state exposed
  • full keyboard support; focus returns on close
  • touch targets adequate on mobile