Skip to Content

Menu

Menu renders a raised Windows 98 command menu. Compose it from MenuItem actions, MenuCheckboxItem toggles, MenuRadioGroup / MenuRadioItem single-selects, MenuLabel headings, MenuShortcut accelerator hints, MenuSeparator dividers, and MenuSub side-expanding submenus. These same items are what ContextMenu and the window WindowMenuBar render, so their behavior is shared across every menu surface.

Composition

Use the following composition to build a Menu:

Menu ├── MenuItem │ └── MenuShortcut ├── MenuCheckboxItem ├── MenuSeparator ├── MenuLabel ├── MenuRadioGroup │ ├── MenuRadioItem │ └── MenuRadioItem ├── MenuSeparator └── MenuSub ├── MenuSubTrigger └── MenuSubContent ├── MenuItem └── MenuItem

Icons are composed as children — render your own element (<img>, <svg>, …) as the first child of a MenuItem or MenuSubTrigger and size it however you like. Use reserveIconSpace on plain rows so their labels stay aligned with icon-bearing or checkable siblings.

Props

ExportKey propsDescription
MenumaxHeight, HTML menu propsRoot command list with role="menu".
MenuItemdisabled, selected, reserveIconSpaceInteractive or disabled menu row. Compose an icon by rendering it as the first child.
MenuCheckboxItemchecked, onCheckedChange, disabledToggle row with a check indicator (role="menuitemcheckbox").
MenuRadioGroupvalue, onValueChangeSingle-selection wrapper for MenuRadioItems.
MenuRadioItemvalue, disabledSelectable row with a bullet indicator (role="menuitemradio").
MenuLabelHTML li propsNon-interactive group heading.
MenuShortcutHTML span propsRight-aligned accelerator hint placed inside an item.
MenuSeparatorHTML li propsHorizontal divider between command groups.
MenuSubopen, onOpenChange, hoverOpenDelay, hoverCloseDelayOwns submenu open state and hover timers.
MenuSubTriggerdisabled, reserveIconSpaceMenu row that opens a submenu, with a built-in right-side chevron. Compose an icon by rendering it as the first child.
MenuSubContentsideOffset, plus Menu propsPortal-rendered submenu positioned to the right of the trigger, flipping to the left at the viewport edge.

Examples

Command menu

Icons, checkboxes, radios, and shortcuts

Submenus

Scroll-arrow steppers

Viewport edge detection

Hover Accessories

Icons

MenuItem renders icon in a fixed 16px gutter that constrains oversized images (max-width/max-height + object-contain), so pixel-art icons stay centered and aligned with the label instead of clipping. Use reserveIconSpace on sibling items so their text lines up with iconned rows.

ARIA

Menu uses role="menu". Items use role="menuitem", role="menuitemcheckbox", or role="menuitemradio"; toggles and radios expose aria-checked, and disabled items expose aria-disabled. MenuSubTrigger adds aria-haspopup="menu" and toggles aria-expanded. All enabled item roles participate in roving focus and typeahead.

Keyboard

ArrowUp and ArrowDown move focus between enabled items (including checkbox and radio items) and wrap at the ends. Home and End move to the first and last enabled item. Typing printable characters moves focus to the next enabled item whose text starts with the typed buffer. Enter and Space activate the focused item — toggling a MenuCheckboxItem, selecting a MenuRadioItem, or invoking a MenuItem. On a MenuSubTrigger, ArrowRight (or Enter / Space) opens the submenu; inside MenuSubContent, ArrowLeft closes it. Escape dismisses the innermost open submenu.

SSR

Keep selected, checked, disabled, and icon content stable between server and client so focusable items hydrate with the same order and labels. MenuSubContent portals on mount, so it renders client-side only.

Last updated on