Design System Problems

Accessible Popup Menus

January 15, 2026 • 5 min read

Accessible Popup Menus

Accessible popup menus enable keyboard and screen reader users to navigate and select from action lists that appear on demand. Proper implementation requires correct ARIA roles, keyboard patterns, and focus management.

What Are Accessible Popup Menus

Popup menus present a list of actions or options that appear when triggered, typically by clicking a button. Examples include more actions menus, context menus, and dropdown menus that execute actions (as opposed to navigation menus or form selects).

The ARIA menu pattern uses role=“menu” for the container and role=“menuitem” for each action. A menu button with aria-haspopup=“menu” triggers the menu. This pattern differs from navigation menus (lists of links) and select dropdowns (form controls).

WCAG requirements include keyboard operability (2.1.1) and proper role/state communication (4.1.2). The menu pattern must support complete keyboard navigation without mouse interaction.

How Accessible Popup Menus Work

The menu button trigger uses aria-haspopup=“menu” to indicate it opens a menu. aria-expanded communicates whether the menu is open or closed. When activated with Enter, Space, or arrow keys, the menu appears.

The menu container uses role=“menu” and contains children with role=“menuitem”. Optionally, role=“menuitemcheckbox” or role=“menuitemradio” can indicate selectable options within the menu.

Keyboard navigation within the menu follows these patterns:

Focus management differs from tab-based navigation. The menu uses roving tabindex: only one item has tabindex=“0” at a time, and arrow keys move this designation. Tab should close the menu rather than move between items.

When the menu opens, focus should move to the first menu item (or a previously selected item if relevant). When the menu closes, focus returns to the trigger button.

Key Considerations

Common Questions

When should menu versus listbox patterns be used?

Menu (role=“menu”) is appropriate for actions: commands that execute when selected. “Edit,” “Delete,” and “Share” are menu items. The menu closes after selection, and the action executes.

Listbox (role=“listbox”) is appropriate for selection: choosing values from a list. Form selects and dropdown value pickers use listbox. The pattern for keyboard navigation differs slightly between these roles.

How should nested submenus work?

Submenus add complexity to popup menus. A menu item that triggers a submenu uses aria-haspopup=“menu” and aria-expanded. Right arrow opens the submenu (left arrow in RTL). Left arrow closes the submenu and returns to parent.

Focus moves into the submenu when it opens. Escape closes only the current level, returning to the parent menu. Deeply nested menus become difficult to navigate; limiting nesting depth improves usability.

Type-ahead allows users to type characters to jump to matching menu items. This feature helps navigate long menus quickly. Typing “d” moves focus to the first item starting with “d.”

Type-ahead is optional but improves usability for longer menus. Implementation watches for character keys and moves focus to matching items. A brief delay between characters allows multi-character searches.

Summary

Accessible popup menus use the ARIA menu pattern with proper roles, arrow key navigation, and focus management that moves focus into the menu on open and returns it to the trigger on close. The pattern suits action lists that execute commands, distinct from navigation menus and selection dropdowns.

Buoy scans your codebase for design system inconsistencies before they ship

Detect Design Drift Free
← Back to Accessibility Compliance