Menu displays a dropdown menu with a list of actions, options, or navigation items that users can select. It provides a flexible dropdown interface supporting multiple item types, trigger variants, and advanced features like search and submenu navigation. Built on Radix UI's DropdownMenu component, it ensures consistent menu patterns across the interface with full keyboard and screen reader support.
Props
Name
Type
Default
Description
children
ReactNode
—
Trigger, content, and any other parts.
anchor
HTMLElement | null
—
Element the content is placed against instead of the trigger, such as a whole split button opened from its
chevron. It must be in the trigger's document. null or omitted anchors to the trigger.
anchorPoint
PopupAnchorPoint | null
—
Viewport point the content opens at, for a menu opened from a pointer position such as a context menu. It
replaces the trigger as the anchor, so the menu is placed with the measured fallback and needs no
{@link MenuTrigger }. The point is in the viewport of the document that holds the menu: the anchor's, else the one the content renders in. The point is read while the menu is open; give a new { x, y } to move it. null or omitted
anchors to the trigger.
defaultOpen
boolean
false
Initial open state when uncontrolled.
onOpenChange
MenuOpenChangeHandler
—
Called on trigger press ("trigger-press"), item press ("item-press"), Tab ("focus-out"), and Escape or an
outside press ("light-dismiss", not cancelable).
open
boolean
—
Controlled open state. Pair with onOpenChange.
Storybook
Interactive examples and edge cases for this component are in Storybook.
Class applied to the dropdown content container. Prefer this for styling the panel; do not pass className or style through contentProps.
contentProps
Props forwarded to Radix DropdownMenu.Content (for example pointer handlers for hover menus). Omit keys the menu owns: className, style, children, and dangerouslySetInnerHTML. NavigableMenu and NavMenu inherit this prop — do not re-declare it on those types.
NavigableMenu Props
Inherits all Menu props plus:
Name
Default
Description
searchable
false
Whether to show a search input at the top of the menu.
searchPlaceholder
"Search..."
Placeholder text for the search input. LocalizedMessage—copy from formatMessage.
onSearchChange
Callback fired when search input value changes: (searchValue: string, submenuKey: string | null) => void. submenuKey is the open submenu’s stable id (or label) when nested, otherwise null at the root.
disableClientFiltering
true when onSearchChange is set
Disables built-in client-side filtering. Pass a boolean to override, or (submenuKey: string | null) => boolean so only some submenus are server-filtered while the root and other submenus keep client filtering.
Reorderable menu props
Menu and NavigableMenu accept these props when items should be reordered by drag or keyboard:
Name
Default
Description
sortable
false
Enables drag handles, drop indicators, and keyboard reorder for items with a sortableId.
onReorder
Called with the new ordered list of sortableId values after a drag or keyboard drop: (orderedIds: string[]) => void.
onReorder reports every id in the reordered list, so handlers can replace their list outright. In
a NavigableMenu, reorder affordances are therefore hidden whenever the visible list is only part
of the list: while a search filter is active, and while a submenu pane is open. Reorder the full
root list instead.
MenuItem Props
Name
Default
Description
onSelect
Callback fired when the item is selected.
disabled
false
Whether the item is disabled.
icon
Optional SVG asset icon displayed before the item label.
current
false
Marks the item as the current page with aria-current="page" and current-item treatment.
children
required
Item label text or content.
sortableId
Stable id for reordering when the parent menu has sortable. Defaults to item label text when omitted.
MenuItemSubmenu Props
Name
Default
Description
label
required
Submenu trigger label text. LocalizedMessage | DisplayValue—copy from formatMessage, or data from toDisplayValue.
disabled
false
Whether the submenu trigger is disabled.
icon
Optional SVG asset icon displayed before the label.
children
required
Menu items to display in the submenu. Note: Only works with NavigableMenu.
MenuItemCheckbox Props
Name
Default
Description
label
required
Checkbox label text. LocalizedMessage | DisplayValue—copy from formatMessage, or data from toDisplayValue.
checked
false
boolean | "indeterminate". "indeterminate" shows the partial-selection dash and announces aria-checked="mixed".
value
Stable identifier. Read by MenuCollapsibleGroup select-all to scope a toggle to filtered children, and used as the default sortableId.
icon
Optional decorative SVG icon displayed before the label. Stays aria-hidden so the accessible name is the label alone.
indicator
MenuItemCheckboxIndicator.Checkbox
Trailing selection indicator. Checkbox uses CheckboxVisual; Checkmark renders an owned in-flow check matching radio rows.
disabled
false
Whether the checkbox is disabled.
onCheckedChange
Callback fired when checkbox state changes: (checked: boolean) => void.
sortableId
Stable id for reordering when the parent menu has sortable. Defaults to value or label when omitted. Checkbox rows drag from the handle only; activating the row still toggles its checked state.
Default indicator is CheckboxVisual—decorative paint, not a nested interactive checkbox. Selection semantics stay on the menuitemcheckbox. Use MenuItemCheckboxIndicator.Checkmark when the row should match radio trailing checkmarks (e.g. single-select group menus). That variant paints an owned in-flow icon; it does not un-hide Radix Themes' private indicator class. Sortable checkbox rows preserve the same checkmark styling while adding the drag affordance.
MenuItemSwitch Props
Name
Default
Description
label
required
Switch label text. LocalizedMessage | DisplayValue—copy from formatMessage, or data from toDisplayValue.
checked
false
Whether the switch is checked.
value
Optional value for the switch item.
disabled
false
Whether the switch is disabled.
onCheckedChange
Callback fired when switch state changes: (checked: boolean) => void.
The toggle is SwitchVisual—decorative paint, not a nested interactive switch. Selection semantics stay on the menuitemcheckbox.
MenuItemRadio Props
Name
Default
Description
value
required
Radio item value.
label
required
Radio item label text. LocalizedMessage | DisplayValue—copy from formatMessage, or data from toDisplayValue.
icon
Optional decorative SVG icon displayed before the label. Stays aria-hidden so the accessible name is the label alone.
trailing
Optional decorative content rendered before the checkmark. The trailing cluster is aria-hidden. Must not introduce nested interactive roles; consumers own pointer isolation when the trailing region handles clicks separately from row selection. Keyboard extras belong on onKeyDown.
aria-label
label
Accessible name override. Keep label as the visible text. LocalizedMessage—copy from formatMessage.
description
Accessible description announced after the name via aria-describedby and a visually hidden node. Rendered after the visible label. Type-ahead uses label, not this string. LocalizedMessage | DisplayValue—copy from formatMessage, or data from toDisplayValue.
disabled
false
Whether the radio item is disabled.
onSelect
Optional callback fired when the radio item is selected.
onKeyDown
Optional keyboard handler on the radio item (for example ArrowLeft/ArrowRight for a consumer-owned extra action).
MenuLabel Props
Name
Default
Description
children
required
Label text displayed as a heading within the menu. When the label follows earlier menu content, block-start spacing uses the --space-12 token so the caption reads as the heading for the rows below; the first label in a level and labels immediately after MenuSeparator keep --space-4 block-start.
MenuGroup Props
Name
Default
Description
value
Currently selected value for radio items within the group.
onValueChange
Callback fired when radio selection changes within the group: (value: string) => void.
children
required
Radio items to display in the group.
MenuCollapsibleGroup Props
A group heading that expands in place and carries a tri-state select-all for its children. Use
this when options should stay in one pane; use MenuItemSubmenu when they
belong on their own pane behind a breadcrumb.
Name
Default
Description
label
required
Group heading, and the accessible name of the select-all row. LocalizedMessage—copy from formatMessage.
groupId
Stable identifier for search indexing and the fallback React key. An explicit consumer key is preserved while filtering. Use groupId when two groups share a label or when a label contains >.
checked
required
Tri-state select-all: boolean | "indeterminate". "indeterminate" announces aria-checked="mixed". Compute it from the whole group; under an active search the group narrows it to the visible children.
onCheckedChange
required
(checked: boolean, visibleValues?: string[]) => void. visibleValues lists the children surviving an active search filter, or is undefined when the toggle applies to the whole group.
caption
Trailing count rendered next to the label, e.g. 13 for "Fire (13)".
disabled
false
Disables the row, select-all, and pointer or keyboard expansion.
defaultOpen
false
Initial expanded state when open is not supplied.
open
Controlled expanded state.
onOpenChange
Fired when the expanded state should change: (open: boolean) => void.
children
required
MenuItemCheckbox rows for the group. Unmounted while collapsed.
The row is a single menuitemcheckbox carrying both aria-checked and aria-expanded. Clicking
anywhere on the row expands or collapses it; clicking the checkbox toggles select-all. Keyboard
and AT activation on a collapsed row expands first; when expanded, Space and Enter toggle
select-all. ArrowRight expands and ArrowLeft collapses.
Inside a searchable NavigableMenu, a group whose children match the query
keeps its real header, auto-expands, and scopes select-all to the surviving rows. Give each child a
value so the group can identify them: the row's own tri-state is then read from the visible
children, so a fully selected subset of a partially selected group still announces checked and
toggles off rather than appearing stuck at mixed.
Expanding a group or scrolling its children never resizes or shifts the root menu panel; panel width
is stable for the life of the open menu.
Menu with Collapsible Groups
Group hundreds of options under expandable categories, each with its own select-all.
Basic Menu
Use for simple dropdown menus with action items.
Menu with Icons
Add icons to menu items for visual clarity and quick recognition.
Menu with Groups and Labels
Organize menu items into logical sections using labels and groups.
Reorderable menu
Use when operators should persist a custom order (for example column visibility lists). Pass sortable on Menu or NavigableMenu, give each item a stable sortableId, and update your data from onReorder.
Menu with Checkboxes
Use checkboxes for multi-select options.
Menu with Radio Groups
Use radio groups for single-select options with controlled state. Pass icon for a decorative leading glyph — the accessible name remains the label.
Trigger Variants
Choose the appropriate trigger based on context and design requirements.
Dropdown Trigger
Default trigger with label and chevron icon.
Button Trigger
Use for primary actions or when the menu acts as a button group.
Icon Button Trigger
Use for compact spaces or secondary actions.
Custom Trigger
Use when you need full control over the trigger element.
NavigableMenu with Search
Enable search functionality for menus with many items.
NavigableMenu with Submenus
Create nested menus with breadcrumb navigation.
Searchable Menu with Submenus
Combine search and submenu navigation for complex menu hierarchies.
Disabled Menu
Disable the entire menu when actions are unavailable.
Disabled Menu Items
Disable specific items while keeping others available.
@prepared911/ui Menu in a toolbar
In @prepared911/ui, put ToolbarItem outside MenuTrigger, with Menu wrapping both the item and MenuContent. MenuTrigger still takes only children; it forwards roving props from the item to the control child so the trigger is one toolbar tab stop. Put menu triggers in a horizontal toolbar; in a vertical toolbar Arrow Down and Arrow Up open the menu instead of moving between items.