API and Development
ContextMenu wraps trigger content and renders actions in ContextMenu.Content. Compose with ContextMenuItem, ContextMenuItemCheckbox, ContextMenuItemSwitch, ContextMenuItemRadio, ContextMenuItemSubmenu, ContextMenuLabel, ContextMenuSeparator, and ContextMenuGroup. For radio groups, pass radioValue and onRadioValueChange. NavigableContextMenu adds advanced navigation patterns for large menus.
Pass contentProps to forward attributes onto the portaled Radix content — for example data-* markers so overlay systems (annotation capture) treat the open menu as exempt. This mirrors Menu's contentProps API.
| Name | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | One {@link ContextMenuTrigger }, one {@link ContextMenuContent }, and any other parts. |
defaultOpen | boolean | false | Initial open state when uncontrolled. |
disabled | boolean | false | Leaves the platform's own context menu alone. The region opens nothing, and its contextmenu event is not
canceled. An open menu closes when this becomes true. |
onOpenChange | MenuOpenChangeHandler | — | Called when the menu opens or closes. Every opening gesture (right click, two-finger tap, Shift+F10, the context
menu key, a long press) reports "trigger-press" with the platform event in details.event; a close reports
"item-press", "focus-out" (Tab), or "light-dismiss" (Escape, an outside press, or a scroll of the region). |
open | boolean | — | Controlled open state. Pair with onOpenChange. |
replaceTextFieldMenu | boolean | false | Opens over native text fields too. By default a right click, Shift+F10, or long press on a text input, a
textarea, or editable content leaves the platform's text menu (cut, copy, paste, spelling) alone and this region
takes nothing, so a form inside a region keeps its editing menu. Set true on a region that must replace it. |
ContextMenu and NavigableContextMenu accept the same reorder props as Menu:
| 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: (orderedIds: string[]) => void. |
ContextMenuItem and ContextMenuItemCheckbox accept sortableId (defaults to label or value when omitted). Checkbox rows drag from the handle only; activating the row still toggles its checked state.
onReorder reports every id in the reordered list, so handlers can replace their list outright. In
a NavigableContextMenu, 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.
| Name | Default | Description |
|---|---|---|
label | required | Checkbox label text, and the row's accessible name. 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 ContextMenuCollapsibleGroup select-all to scope a toggle to filtered children. | |
disabled | false | Disables the row. |
onCheckedChange | (checked: boolean) => void. Never receives "indeterminate" — activation always resolves to a definite state. |
menuitemcheckbox; the checkbox is painted with the non-interactive
CheckboxVisual, so there is no nested focusable to break Radix's roving tabindex.
ContextMenuItemSubmenu when they belong on their own
pane behind a breadcrumb. The ContextMenu counterpart of
MenuCollapsibleGroup, with the same
semantics.
| 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 and its select-all. |
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 | ContextMenuItemCheckbox rows for the group. Unmounted while collapsed. |
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 NavigableContextMenu, a group with matching children keeps its own header,
auto-expands, and scopes select-all to the surviving matches rather than the whole group. 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.