Skip to content
← UI patterns

Dropdown Menu

A button that reveals a short list of commands on a temporary surface, then collapses once one is chosen.

Open the menu, then use the Up/Down arrows, type-ahead, Enter, or Esc.

A real menu button, live. The trigger carries aria-haspopup and aria-expanded; opening moves focus into a role=menu navigated by arrow keys, with Esc returning focus to the trigger.

Current density: Comfortable. A short action menu keeps a related set of choices one click away without spending resting space.

The same widget for a short set of view options. A menu invokes a choice; for selecting a persistent form value a listbox or select would be the right pattern.

Behavior

Keyboard

Enter / Space
On the trigger, open the menu and focus the first item. On an item with a submenu, open it. On a normal item, activate it and close the menu.
Down / Up Arrow
On the trigger (optional), open the menu and focus the first or last item. In the menu, move focus to the next or previous item, optionally wrapping at the ends.
Home / End
Move focus to the first or last item in the menu.
Character keys
Type-ahead: move focus to the next item whose label begins with the typed printable character.
Right / Left Arrow
On an item with a submenu, Right opens it and Left closes it. In a horizontal menubar, they move between top-level items.
Escape
Close the menu and return focus to the trigger from which it was opened.
Tab / Shift+Tab
Move focus out of the menu and close it. Tab does not move between items inside the menu.
Parts

Menu button / trigger

The persistent control that opens the menu. It carries role=button, aria-haspopup=menu, and aria-expanded reflecting open or closed state, and usually shows a caret to hint a menu will appear.

Menu / popup surface

The temporary container with role=menu, labelled via aria-labelledby pointing at the trigger or via aria-label. It is a composite widget that owns focus internally and is vertical by default.

Menu item

Each choice, with role=menuitem, or menuitemcheckbox and menuitemradio for toggles and exclusive sets. Every item needs an accessible name, taken from its contents by default.

Separator / group

A role=separator divides item groups (notably radio sets); separators are not focusable or interactive. Disabled items use aria-disabled=true and stay focusable but cannot be activated.

Submenu (cascading)

A parent menuitem with aria-haspopup=menu and aria-expanded opens a nested role=menu placed immediately after it in the DOM, reached with Right Arrow.

States

Open / closed

The trigger toggles the surface; aria-expanded is true while shown and false while hidden. On open, focus moves into the menu (first item via Enter, Space, or Down Arrow; last item via Up Arrow). On close, focus returns to the trigger.

Highlight and current item

Items show a focus or active highlight as the user arrows or hovers through them, with only one item current at a time, managed via a roving tabindex or aria-activedescendant.

Submenu open and type-ahead

A parent item opens its submenu on Right Arrow or Enter, moving focus to the submenu's first item; Left Arrow or Escape closes it and returns to the parent. Pressing a printable character moves focus to the next item whose label begins with that character.

Positioning and disabled items

The surface is positioned next to the trigger and should reposition to stay on screen, with a max height at least one row short of the viewport so it never fully covers the UI. Unavailable items are grayed out and kept in place for spatial consistency rather than removed.

References

The W3C APG actions menu button, opened: an Actions trigger above a menu listing Action 1 through Action 4, with the first item highlighted.
APG: actions menu button exampleW3C WAI
The W3C APG editor menubar with the Font menu open: a horizontal bar of Font, Style/Color, Text Align, and Size above a dropdown of Sans-serif (selected), Serif, Monospace, and Fantasy, over a block of editor text.
APG: editor menubar exampleW3C WAI
Material 3 menus: a dropdown of Revert, Delete, Settings, and Help and feedback on a phone screen, beside a cascading menu where Create expands to Document, Image, and Slides with Offline mode checked.
Material Design 3 menusGoogle

Use it

Figma
A menu item as a component set with states
  1. Create one Menu Item component, then add a State variant property: Default, Hover, Focus, and Disabled.
  2. Optionally add a Type property: action, checkbox, radio, and with-submenu.
  3. Use Auto Layout so the item grows with its label and can hold a leading icon plus a trailing caret or shortcut.
  4. Give Hover and Focus visibly different treatments, matching focus to the arrow-key position in the keyboard model.

Naming Focus distinctly from Hover keeps the spec honest for handoff, since arrow-key focus and pointer hover are different states in a real menu.

Assemble the surface with Auto Layout
  1. Make a Menu frame with vertical Auto Layout and instance your Menu Item components into it.
  2. Insert a thin divider component between groups and name it Separator so it maps to role=separator.
  3. Set padding, corner radius, and an elevation or shadow style.
  4. Set a max height with Clip content so long menus scroll, mirroring the guidance to stay a row short of the viewport.

Reuse the same Menu and Menu Item components for submenus so a nested menu inherits every state automatically.

Wire the open and closed states for prototyping
  1. Make the trigger a component with an Expanded property: false and true (the caret rotates and the background activates on true).
  2. Use an interactive overlay or component property so clicking the trigger shows the Menu anchored to it.
  3. Set the overlay to close on click outside and on Esc.
  4. Add a handoff note recording aria-haspopup and aria-expanded so engineers keep the disclosure contract.

Model submenus as a nested Menu overlay positioned to the parent item's right edge, opened from the with-submenu variant, and keep nesting to one level.

Accessibility

The accessible dropdown is the WAI-ARIA menu-button pattern. Because browsers give no automatic keyboard behavior to ARIA widgets, the author must build the full keyboard model, manage focus, and return focus to the trigger on close. Use this pattern only for genuine action menus: do not apply role=menu to site navigation or to value selection, where it makes the interface less accessible, not more.

  1. On close, always return focus to the trigger so keyboard users are not stranded where the menu used to be.
  2. Do not use menu, menubar, or menuitem roles for site navigation: use a nav with a list of links, optionally a disclosure widget. Menu roles advertise desktop-style key commands that do not belong on a normal page.
  3. A native select and a custom combobox are not menus; repurposing a select for navigation causes an unexpected change of context.
  4. Keep nesting shallow: one tier of submenu is fine, two gets frustrating, and more than two is inadvisable.
Research notes & sources

WAI-ARIA Menu Button: button[aria-haspopup][aria-expanded] opens role=menu of role=menuitem, arrow-key navigation

  1. Menu Button Pattern (ARIA Authoring Practices Guide)W3C WAI
  2. Menu and Menubar Pattern (ARIA Authoring Practices Guide)W3C WAI
  3. Developing a Keyboard Interface (ARIA Authoring Practices Guide)W3C WAI
  4. Actions Menu Button Example Using element.focus()W3C WAI
  5. Editor Menubar ExampleW3C WAI
  6. ARIA: menu roleMDN Web Docs
  7. Dropdowns: Design GuidelinesNielsen Norman Group
  8. Don't Use ARIA Menu Roles for Site Navadrianroselli.com
  9. Menus & Menu ButtonsInclusive Components
  10. Action list componentShopify Polaris
  11. MenusMaterial Design 3 (Google)