Navigation
Menu
Menu is a compact command surface for contextual actions — distinct from Select (form values) and Popover (supplementary content).
Placement (bottom default) · Item states (Default/Hover/Disabled/Destructive)
betaReact AvailableFigma AvailableDocs Partial
- React last updated
- 2026-07-12
- Documentation last updated
- 2026-06-01
- Accessibility target
- WCAG 2.2 AA (target)
- Version
- 0.4.0-beta
Known open questions
- Checkbox and radio menu items are not confirmed in Figma — deferred.
- Submenus and Context Menu are separate future components.
- Dropdown Menu is documented as a usage pattern, not a duplicate public component.
Live preview
Menu is a compact command list — not for navigation landmarks or form value selection. Dropdown Menu is this same Menu pattern opened from a trigger.
Project actions
Last action: No action yet
Disabled item and keyboard navigation
Groups and separators
Controlled open state
Long menu with internal scrolling
Menu inside Dialog
Purpose
A compact collection of commands or actions opened from a trigger — use for application commands, contextual actions, overflow menus, and item-specific operations.
Anatomy
Menu = trigger button + floating menu surface + menuitem rows with optional icons, shortcuts, groups, labels, and separators.
Variants and states
default · destructive
When to use
Application commands, contextual actions, overflow actions, view or sorting commands, and item-specific operations that execute immediately.
When not to use
Ordinary site navigation, article link lists, form option selection (use Select), tabs, breadcrumbs, sidebar navigation, long content, or complex forms.
Accessibility
role="menu" on the menu surface with role="menuitem" rows, aria-haspopup="menu" and aria-expanded on the trigger, roving keyboard focus, typeahead search, Escape dismissal, and Tab exits without trapping focus.
Keyboard behavior
Arrow Up/Down move between enabled items. Home/End jump to boundaries. Enter and Space activate. Printable keys typeahead-match item labels. Escape closes and restores trigger focus. Tab and Shift+Tab close without trapping focus.
Common mistakes
Using Menu for primary navigation links, using Menu where Select is needed for form values, or nesting interactive controls inside menu items.
Properties
Compound API: Menu, MenuTrigger, MenuContent, MenuItem, MenuGroup, MenuLabel, MenuSeparator. MenuItem supports icon, shortcut, destructive styling, disabled state, and onSelect.
What is the difference between Menu and Popover?
Menu contains commands with menuitem semantics and a managed keyboard model. Popover holds supplementary or interactive content without command-list semantics.
What is the difference between Menu and Select?
Select chooses one form field value with combobox/listbox semantics. Menu executes commands and does not submit a single canonical field value.
Should ordinary navigation links use Menu semantics?
No. Persistent navigation belongs in nav landmarks, breadcrumbs, or tabs. Menu is for transient command lists.
Does Tab move through Menu items?
No. Tab closes the Menu and continues normal document focus order.
Tokens used
menu/surfacemenu/item-textmenu/item-hover-surfacesemantic/focus-ringsemantic/action/danger
Component API
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | — | Controlled open state. |
| defaultOpen | boolean | — | Initial open state. |
| onOpenChange | (open: boolean) => void | — | Open state callback. |
| placement | PopoverPlacement | "bottom" | Preferred placement. |
| align | PopoverAlign | "start" | Alignment relative to trigger. |
| loop | boolean | false | Whether arrow navigation wraps. |
| closeOnSelect | boolean | true | Close after item activation. |
| onSelect | (event: Event) => void | — | MenuItem activation callback. |
React example
Copy React example
"use client";
import {
Menu,
MenuContent,
MenuItem,
MenuSeparator,
MenuTrigger,
} from "@/components/ui/Menu";
import { Button } from "@/components/ui/Button";
export function Example() {
return (
<Menu>
<MenuTrigger>
<Button type="button">Project actions</Button>
</MenuTrigger>
<MenuContent>
<MenuItem onSelect={() => {}}>Edit profile</MenuItem>
<MenuItem onSelect={() => {}}>Duplicate</MenuItem>
<MenuSeparator />
<MenuItem destructive onSelect={() => {}}>
Delete project
</MenuItem>
</MenuContent>
</Menu>
);
}