Menu

Accessible dropdown action menus following the WAI-ARIA Menu Button pattern, featuring roving focus keyboard navigation, shortcut keys, danger states, and focus return.

Interactive Preview

Interactive Preview

Interactive Preview

API reference

MenuProps

triggerReact.ReactNode

Name: trigger

Description: The trigger element (e.g. <Button>). Automatically wired with accessibility attributes.

Type: React.ReactNode

Default:

childrenReact.ReactNode

Name: children

Description: Menu content containing MenuItem, MenuDivider, and MenuGroup.

Type: React.ReactNode

Default:

labelstring

Name: label

Description: Accessible label for the menu if trigger does not contain visible text.

Type: string

Default:

isOpenboolean

Name: isOpen

Description: Controlled open state.

Type: boolean

Default:

defaultOpenbooleanfalse

Name: defaultOpen

Description: Initial open state when uncontrolled.

Type: boolean

Default: false

onOpenChange(isOpen: boolean) => void

Name: onOpenChange

Description: Callback fired when open state changes.

Type: (isOpen: boolean) => void

Default:

placement'bottom-start' | 'bottom-end' | 'top-start' | 'top-end''bottom-start'

Name: placement

Description: Alignment of dropdown menu relative to the trigger.

Type: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'

Default: 'bottom-start'

closeOnSelectbooleantrue

Name: closeOnSelect

Description: Whether selecting a menu item automatically closes the menu.

Type: boolean

Default: true

MenuItemProps

childrenReact.ReactNode

Name: children

Description: Item label text or elements.

Type: React.ReactNode

Default:

onClick(event: React.MouseEvent | React.KeyboardEvent) => void

Name: onClick

Description: Action handler invoked on click, Enter, or Space.

Type: (event: React.MouseEvent | React.KeyboardEvent) => void

Default:

hrefstring

Name: href

Description: Optional destination URL to render as an accessible navigation link.

Type: string

Default:

iconReact.ReactNode

Name: icon

Description: Optional leading icon or SVG element.

Type: React.ReactNode

Default:

shortcutstring

Name: shortcut

Description: Optional keyboard shortcut label (e.g. ⌘S).

Type: string

Default:

disabledbooleanfalse

Name: disabled

Description: Disables interaction and skips the item during keyboard navigation.

Type: boolean

Default: false

dangerbooleanfalse

Name: danger

Description: Applies destructive danger styling for critical actions (e.g. Delete).

Type: boolean

Default: false

MenuGroupProps

labelstring

Name: label

Description: Optional section header text associated via aria-labelledby.

Type: string

Default:

childrenReact.ReactNode

Name: children

Description: Group content items.

Type: React.ReactNode

Default:

KeyFocus TargetBehavior
Enter / Space / Trigger ButtonOpens menu and moves focus to the first non-disabled item.
Trigger ButtonOpens menu and moves focus to the last non-disabled item.
Menu ItemMoves focus to the next item, skipping disabled items and wrapping around.
Menu ItemMoves focus to the previous item, skipping disabled items and wrapping around.
HomeMenu ItemJumps focus to the first non-disabled item.
EndMenu ItemJumps focus to the last non-disabled item.
EscapeMenu ItemCloses menu and immediately returns focus to the trigger button.
TabMenu ItemCloses menu and allows normal tab order progression.
  • Trigger Semantics: Configured with aria-haspopup="menu" and aria-expanded.
  • Roving Tabindex: Only the active item receives focus during arrow key navigation; pressing Tab doesn't trap keyboard focus inside the menu.
  • Focus Return (WCAG 2.4.3): Dismissing via Escape or activating an action item returns focus directly to the trigger button.
  • Semantic Groups & Dividers: Uses role="group" with accessible section headers and role="separator" for dividing lines.
  • Zero 3rd-Party Dependencies: Native React and CSS implementation with zero external runtime footprint.
Open Menu stories in Storybook