Prepared Docs

Prepared Docs

⌘K

    Loading navigation…

User

  1. Components
  2. Menu
  3. Accessibility
  4. General

Menu

General

Menu from @prepared911/ui-core is a Radix Dropdown Menu. The primitive wires menu roles, keyboard flow, and focus trap; your job is to keep item labels clear, name icon-only items, and avoid menus whose only discoverable path is hover.

What the component handles

  • Menu semantics. Content exposes role="menu"; items expose role="menuitem", menuitemcheckbox, or menuitemradio.
  • Focus trap. Focus moves into the menu on open and returns to the trigger on close.
  • Keyboard flow. Arrow keys navigate, Escape closes, Enter/Space activate, type-ahead jumps by the visible item label's first letter. MenuItemRadio description does not change type-ahead.
  • Submenu handling. Arrow Right opens; Arrow Left returns.

What you must provide

  • A real button trigger. Use Button or IconButton so the trigger exposes aria-haspopup="menu" and aria-expanded.
  • Readable item labels. Verb-first phrases ("Edit incident", "Copy link"). Don't hide the only label behind an icon.
  • Toggle and choice items. Use MenuItemCheckbox, MenuItemSwitch, or MenuItemRadio—see Interactive MenuItem children. Do not nest a separate interactive checkbox, switch, or radio inside a menu item.
  • Keyboard parity. Every menu action must be reachable by keyboard; don't rely on pointer-only gestures.

Interactive MenuItem children

Checkbox, switch, and radio rows are still one interactive widget: the menu item itself. Nesting a real Checkbox, Switch, or radio control inside a MenuItem creates a nested-interactive violation—screen readers and keyboard focus then see two controls where there should be one.

Use the menu item primitives

NeedComponentRoleVisual indicator
Multi-select / independent on-offMenuItemCheckboxmenuitemcheckboxCheckboxVisual
Persistent preference toggleMenuItemSwitchmenuitemcheckboxSwitchVisual
Single choice in a setMenuItemRadio inside MenuGroupmenuitemradioDecorative radio mark
Select-all over an expandable categoryMenuCollapsibleGroupmenuitemcheckbox + aria-expandedCheckboxVisual, tri-state

MenuItemSwitch paints like a switch for sighted users but uses the same Radix checkbox-item primitive as MenuItemCheckbox, so assistive tech still gets menuitemcheckbox + aria-checked.

Rules

  • One interactive target per row. Focus, activation (Enter/Space), and aria-checked live on the menuitemcheckbox / menuitemradio. Arrow keys move between items; do not add a nested tab stop.
  • Indicators are paint only. CheckboxVisual and SwitchVisual are always aria-hidden. Do not use them as standalone form controls, and do not nest interactive Checkbox / Switch for the checkmark or thumb.
  • Visible state must match aria-checked. Controlled checked (checkbox/switch) or MenuGroup value (radio) drives both the indicator and the announced state. A partial selection must be "indeterminate", which paints the dash and announces aria-checked="mixed"; never round it to checked or unchecked.
  • A collapsible group is still one target. MenuCollapsibleGroup puts aria-checked and aria-expanded on the same row. Its chevron is aria-hidden and pointer-only; keyboard users expand with ArrowRight and collapse with ArrowLeft, so no nested tab stop is introduced.
  • No other nested interactives. Don't put buttons, links, or form fields inside a menu item. Put secondary actions on sibling items or outside the menu. MenuItemRadio trailing is aria-hidden paint; pointer isolation may handle extra clicks, but keyboard extras go on the radio item's onKeyDown. Extra state that trailing represents (for example sort direction) belongs on the radio via aria-label / description.
  • Labels stay on the item. Pass a clear label (or equivalent accessible name). Don't rely on the decorative indicator alone.

For attribute-level detail, see ARIA Attributes. Combobox multi-select overflow rows follow the same decorative-indicator pattern—see Combobox accessibility.

Deep dives

  • Keyboard Support: full shortcut reference, including type-ahead and submenu navigation.
  • ARIA Attributes: roles, states, and label association for items, checkboxes, and radios.
  • Focus Management, Screen Reader Support, and Disabled States cover the remaining runtime behavior.

Known caveats

  • Nested menus that scroll. When a submenu is taller than the viewport, ensure it scrolls internally and preserves keyboard navigation—don't rely on the trigger to follow scroll.
  • Destructive items. Guard destructive items with clear labels and tone ("Delete incident"). Consider a confirm step for irreversible actions rather than placing them behind a single menu click.

Previous

Menu / API and Development

Next

Accessibility / Keyboard Support

On this page

What the component handles
What you must provide
Interactive MenuItem children
Use the menu item primitives
Rules
Deep dives
Known caveats