Context Menu
A menu that appears at the pointer on right click or long press.
import { ContextMenu } from 'base-ui-solid/context-menu';
import styles from './index.module.css';
export default function ExampleMenu() {
return (
<ContextMenu.Root>
<ContextMenu.Trigger class={styles.Trigger}>Right click here</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Positioner class={styles.Positioner}>
<ContextMenu.Popup class={styles.Popup}>
<ContextMenu.Item class={styles.Item}>Add to Library</ContextMenu.Item>
<ContextMenu.Item class={styles.Item}>Add to Playlist</ContextMenu.Item>
<ContextMenu.Separator class={styles.Separator} />
<ContextMenu.Item class={styles.Item}>Play Next</ContextMenu.Item>
<ContextMenu.Item class={styles.Item}>Play Last</ContextMenu.Item>
<ContextMenu.Separator class={styles.Separator} />
<ContextMenu.Item class={styles.Item}>Favorite</ContextMenu.Item>
<ContextMenu.Item class={styles.Item}>Share</ContextMenu.Item>
</ContextMenu.Popup>
</ContextMenu.Positioner>
</ContextMenu.Portal>
</ContextMenu.Root>
);
}
Usage guidelines
- Use context menus as an enhancement: Don’t make a context menu the only way to perform actions. Users may not discover or be able to open a context menu, especially on touch devices or with assistive technology. Always provide visible controls for the actions that are available in the context menu.
Anatomy
Import the components and place them together:
import { ContextMenu } from 'base-ui-solid/context-menu';
<ContextMenu.Root>
<ContextMenu.Trigger />
<ContextMenu.Portal>
<ContextMenu.Backdrop />
<ContextMenu.Positioner>
<ContextMenu.Popup>
<ContextMenu.Arrow />
<ContextMenu.Item />
<ContextMenu.LinkItem />
<ContextMenu.Separator />
<ContextMenu.SubmenuRoot>
<ContextMenu.SubmenuTrigger />
</ContextMenu.SubmenuRoot>
<ContextMenu.Group>
<ContextMenu.GroupLabel />
</ContextMenu.Group>
<ContextMenu.RadioGroup>
<ContextMenu.RadioItem>
<ContextMenu.RadioItemIndicator />
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
<ContextMenu.CheckboxItem>
<ContextMenu.CheckboxItemIndicator />
</ContextMenu.CheckboxItem>
</ContextMenu.Popup>
</ContextMenu.Positioner>
</ContextMenu.Portal>
</ContextMenu.Root>;
Examples
Menu displays additional demos, many of which apply to the context menu as well.
Using with Menu
A context menu should supplement a primary way to perform the same actions. This image card exposes actions through a visible menu button and reuses them in the context menu for right-click and long-press users.
Station Hofplein
JPG, 2.4 MB
import { untrack, For } from 'solid-js';
import type { JSX } from '@solidjs/web';
import { ContextMenu } from 'base-ui-solid/context-menu';
import { Menu } from 'base-ui-solid/menu';
import styles from './index.module.css';
export default function ContextMenuWithMenuDemo() {
return (
<div class={styles.Card}>
<ContextMenu.Root>
<ContextMenu.Trigger>
<img
width="512"
height="288"
class={styles.Image}
src="https://images.unsplash.com/photo-1619615391095-dfa29e1672ef?q=80&w=512&h=288"
alt=""
/>
<div class={styles.Content}>
<p class={styles.Title}>Station Hofplein</p>
<p class={styles.Metadata}>JPG, 2.4 MB</p>
</div>
</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Positioner class={styles.Positioner}>
<ContextMenu.Popup class={styles.Popup}>
<SharedMenuItems type="context-menu" />
</ContextMenu.Popup>
</ContextMenu.Positioner>
</ContextMenu.Portal>
</ContextMenu.Root>
<Menu.Root>
<Menu.Trigger aria-label="Image actions" class={styles.MenuTrigger}>
<MoreVertIcon />
</Menu.Trigger>
<Menu.Portal>
<Menu.Positioner align="end" sideOffset={8} class={styles.Positioner}>
<Menu.Popup class={styles.Popup}>
<SharedMenuItems />
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
</div>
);
}
const actions = ['Preview', 'Download', 'Copy link', 'Rename'];
function SharedMenuItems(props: { type?: 'menu' | 'context-menu' }) {
const Item = untrack(() => (props.type === 'context-menu' ? ContextMenu.Item : Menu.Item));
const Separator = untrack(() =>
props.type === 'context-menu' ? ContextMenu.Separator : Menu.Separator,
);
return (
<>
<For each={actions}>{(action) => <Item class={styles.Item}>{action}</Item>}</For>
<Separator class={styles.Separator} />
<Item class={[styles.Item, styles.ItemDestructive]}>Delete</Item>
</>
);
}
function MoreVertIcon(props: JSX.IntrinsicElements['svg']) {
return (
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props}>
<path d="M9.5 13c0 .8284-.67157 1.5-1.5 1.5s-1.5-.6716-1.5-1.5.67157-1.5 1.5-1.5 1.5.6716 1.5 1.5m0-5c0 .82843-.67157 1.5-1.5 1.5S6.5 8.82843 6.5 8 7.17157 6.5 8 6.5s1.5.67157 1.5 1.5m0-5c0 .82843-.67157 1.5-1.5 1.5S6.5 3.82843 6.5 3 7.17157 1.5 8 1.5s1.5.67157 1.5 1.5" />
</svg>
);
}
Nested menu
To create a submenu, create a <ContextMenu.SubmenuRoot> inside the parent context menu. Use the <ContextMenu.SubmenuTrigger> part for the menu item that opens the nested menu.
import { mergeProps } from 'base-ui-solid/merge-props';
import type { JSX } from '@solidjs/web';
import { ContextMenu } from 'base-ui-solid/context-menu';
import styles from './index.module.css';
export default function ExampleContextMenu() {
return (
<ContextMenu.Root>
<ContextMenu.Trigger class={styles.Trigger}>Right click here</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Positioner class={styles.Positioner}>
<ContextMenu.Popup class={styles.Popup}>
<ContextMenu.Item class={styles.Item}>Add to Library</ContextMenu.Item>
<ContextMenu.SubmenuRoot>
<ContextMenu.SubmenuTrigger class={styles.SubmenuTrigger}>
Add to Playlist
<CaretRightIcon />
</ContextMenu.SubmenuTrigger>
<ContextMenu.Portal>
<ContextMenu.Positioner class={styles.Positioner} alignOffset={-4} sideOffset={-4}>
<ContextMenu.Popup class={styles.SubmenuPopup}>
<ContextMenu.Item class={styles.Item}>Get Up!</ContextMenu.Item>
<ContextMenu.Item class={styles.Item}>Inside Out</ContextMenu.Item>
<ContextMenu.Item class={styles.Item}>Night Beats</ContextMenu.Item>
<ContextMenu.Separator class={styles.Separator} />
<ContextMenu.Item class={styles.Item}>New playlist…</ContextMenu.Item>
</ContextMenu.Popup>
</ContextMenu.Positioner>
</ContextMenu.Portal>
</ContextMenu.SubmenuRoot>
<ContextMenu.Separator class={styles.Separator} />
<ContextMenu.Item class={styles.Item}>Play Next</ContextMenu.Item>
<ContextMenu.Item class={styles.Item}>Play Last</ContextMenu.Item>
<ContextMenu.Separator class={styles.Separator} />
<ContextMenu.Item class={styles.Item}>Favorite</ContextMenu.Item>
<ContextMenu.Item class={styles.Item}>Share</ContextMenu.Item>
</ContextMenu.Popup>
</ContextMenu.Positioner>
</ContextMenu.Portal>
</ContextMenu.Root>
);
}
function CaretRightIcon(props: JSX.IntrinsicElements['svg']) {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="currentColor"
{...(mergeProps<JSX.IntrinsicElements['svg']>(
{ style: { display: 'block' } },
props,
) as JSX.IntrinsicElements['svg'])}
>
<path d="M6 12V4l4.5 4z" />
</svg>
);
}
API reference
Root
A component that creates a context menu activated by right clicking or long pressing. Doesn’t render its own HTML element.
defaultOpenbooleanfalse
open prop instead.booleanopenboolean—
booleanonOpenChangefunction—
((open: boolean, eventDetails: ContextMenu.Root.ChangeEventDetails) => void)highlightItemOnHoverbooleantrue
:hover to be differentiated from the :focus (data-highlighted) state.booleanactionsRefReact.RefObject<MenuRoot.Actions | null>—
unmount: Ends the closing phase of the menu after an externally controlled closing animation finishes.
Call preventUnmountOnClose() in onOpenChange first, otherwise the menu completes closing on its own.
Whether it leaves the DOM is decided by keepMounted on the portal.close: Closes the menu imperatively when called.highlightItem: Moves or clears the highlight while the menu is open.
'next' and 'previous' move sequentially through the items and wrap unless loopFocus
is disabled. 'first' and 'last' highlight the first or last item. 'none' clears the
highlight and hands focus back to the popup.
Calling this action does not open the menu. To highlight an item after opening it, call
the action from onOpenChangeComplete when open is true.
Highlight changes requested through this action report the reason 'imperative-action'
to onItemHighlighted.React.RefObject<MenuRoot.Actions | null>loopFocusbooleantrue
booleanonItemHighlightedfunction—
undefined if no item is highlighted) and details
containing the reason for the change, the event, and the item’s text label.
The reason can be: 'keyboard': the highlight changed due to keyboard navigation.'pointer': the highlight changed due to pointer hovering. The event may be a MouseEvent
rather than a PointerEvent.'imperative-action': the highlight changed via actionsRef's highlightItem.'none': the highlight changed for another reason, such as automatic highlighting while
filtering, the item list changing, or the popup opening or closing.((highlightedItem: HTMLElement | undefined, eventDetails: MenuRoot.HighlightEventDetails) => void)onOpenChangeCompletefunction—
((open: boolean) => void)disabledbooleanfalse
booleanorientationMenuRoot.Orientation'vertical'
MenuRoot.OrientationchildrenReact.ReactNode—
React.ReactNodeRoot.State
type ContextMenuRootState = {};Root.Actions
type ContextMenuRootActions = {
unmount: () => void;
close: () => void;
highlightItem: (target: ContextMenu.Root.HighlightItemTarget) => void;
};Root.ChangeEventReason
type ContextMenuRootChangeEventReason =
| 'trigger-hover'
| 'trigger-focus'
| 'trigger-press'
| 'outside-press'
| 'focus-out'
| 'list-navigation'
| 'escape-key'
| 'item-press'
| 'close-press'
| 'sibling-open'
| 'cancel-open'
| 'imperative-action'
| 'none';Root.ChangeEventDetails
type ContextMenuRootChangeEventDetails = (
| { reason: 'trigger-hover'; event: MouseEvent }
| { reason: 'trigger-focus'; event: FocusEvent }
| { reason: 'trigger-press'; event: MouseEvent | PointerEvent | TouchEvent | KeyboardEvent }
| { reason: 'outside-press'; event: MouseEvent | PointerEvent | TouchEvent }
| { reason: 'focus-out'; event: FocusEvent | KeyboardEvent }
| { reason: 'list-navigation'; event: KeyboardEvent }
| { reason: 'escape-key'; event: KeyboardEvent }
| { reason: 'item-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'close-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'sibling-open'; event: Event }
| { reason: 'cancel-open'; event: MouseEvent }
| { reason: 'imperative-action'; event: Event }
| { reason: 'none'; event: Event }
) & {
/** Cancels Base UI from handling the event. */
cancel: () => void;
/** Allows the event to propagate in cases where Base UI will stop the propagation. */
allowPropagation: () => void;
/** Indicates whether the event has been canceled. */
isCanceled: boolean;
/** Indicates whether the event is allowed to propagate. */
isPropagationAllowed: boolean;
/** The element that triggered the event, if applicable. */
trigger: Element | undefined;
};Root.HighlightItemTarget
type ContextMenuRootHighlightItemTarget = 'next' | 'previous' | 'first' | 'last' | 'none';Trigger
An area that opens the menu on right click or long press.
Renders a <div> element.
classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-popup-open-—
-data-pressed-—
-Attribute | Description | |
|---|---|---|
data-popup-open | Present when the corresponding context menu is open. | |
data-pressed | Present when the corresponding context menu is open. | |
Trigger.State
type ContextMenuTriggerState = {
/** Whether the context menu is currently open. */
open: boolean;
};Portal
A portal element that moves the popup to a different part of the DOM.
By default, the portal element is appended to <body>.
Renders a <div> element.
containerUnion—
HTMLElement | ShadowRoot | React.RefObject<HTMLElement | ShadowRoot | null> | nullclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)keepMountedbooleanfalse
booleanrenderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Portal.State
type ContextMenuPortalState = {};Backdrop
An overlay displayed beneath the menu popup.
Renders a <div> element.
classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-open-—
-data-closed-—
-data-starting-style-—
-data-ending-style-—
-Attribute | Description | |
|---|---|---|
data-open | Present when the menu is open. | |
data-closed | Present when the menu is closed. | |
data-starting-style | Present when the menu begins animating in. | |
data-ending-style | Present when the menu is animating out. | |
Backdrop.State
type ContextMenuBackdropState = {
/** Whether the menu is currently open. */
open: boolean;
/** The transition status of the component. */
transitionStatus: TransitionStatus;
};Positioner
Positions the context menu popup against the pointer or a custom anchor.
Renders a <div> element.
disableAnchorTrackingbooleanfalse
booleanalignAlign'start'
AlignalignOffsetUnion—
data object parameter with the following properties: data.anchor: the dimensions of the anchor element with properties width and height.data.positioner: the dimensions of the positioner element with properties width and height.data.side: which side of the anchor element the positioner is aligned against.data.align: how the positioner is aligned relative to the specified side. Defaults to 2 for root context menus when side is not specified and align is not
'center'. Otherwise, it defaults to 0.number | OffsetFunctionsideSide'bottom'
'inline-end'.SidesideOffsetUnion—
data object parameter with the following properties: data.anchor: the dimensions of the anchor element with properties width and height.data.positioner: the dimensions of the positioner element with properties width and height.data.side: which side of the anchor element the positioner is aligned against.data.align: how the positioner is aligned relative to the specified side. Defaults to -5 for root context menus when side is not specified and align is not
'center'. Otherwise, it defaults to 0.number | OffsetFunctionarrowPaddingnumber—
0. Submenus default to 5.numberanchorfunction—
Element | VirtualElement | React.RefObject<Element | null> | (() => Element | VirtualElement | null) | nullcollisionAvoidanceCollisionAvoidance—
side controls overflow on the preferred placement axis (top/bottom or left/right): 'flip': keep the requested side when it fits; otherwise try the opposite side
(top and bottom, or left and right).'shift': never change side; keep the requested side and move the popup within
the clipping boundary so it stays visible.'none': do not correct side-axis overflow. align controls overflow on the alignment axis (start/center/end): 'flip': keep side, but swap start and end when the requested alignment overflows.'shift': keep side and requested alignment, then nudge the popup along the
alignment axis to fit.'none': do not correct alignment-axis overflow. fallbackAxisSide controls fallback behavior on the perpendicular axis when the
preferred axis cannot fit: 'start': allow perpendicular fallback and try the logical start side first
(top before bottom, or left before right in LTR).'end': allow perpendicular fallback and try the logical end side first
(bottom before top, or right before left in LTR).'none': do not fallback to the perpendicular axis. When side is 'shift', explicitly setting align only supports 'shift' or 'none'.
If align is omitted, it defaults to 'flip'.CollisionAvoidancecollisionBoundaryBoundary'clipping-ancestors'
BoundarycollisionPaddingPadding5
Paddingstickybooleanfalse
booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-open-—
-data-closed-—
-data-anchor-hidden-—
-data-alignUnion—
'start' | 'center' | 'end'data-sideUnion—
'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start'Attribute | Description | |
|---|---|---|
data-open | Present when the menu popup is open. | |
data-closed | Present when the menu popup is closed. | |
data-anchor-hidden | Present when the anchor is hidden. | |
data-align | Indicates how the popup is aligned relative to the specified side. | |
data-side | Indicates which side the popup is positioned relative to the anchor. | |
CSS variables
--anchor-heightnumber—
number--anchor-widthnumber—
number--available-heightnumber—
number--available-widthnumber—
number--positioner-heightnumber—
height to this value when using CSS to animate size changes.number--positioner-widthnumber—
width to this value when using CSS to animate size changes.number--transform-originstring—
stringCSS Variable | Description | |
|---|---|---|
--anchor-height | The anchor’s height. | |
--anchor-width | The anchor’s width. | |
--available-height | The available height between the anchor and the edge of the viewport. | |
--available-width | The available width between the anchor and the edge of the viewport. | |
--positioner-height | The height of the menu’s positioner.
It is important to set height to this value when using CSS to animate size changes. | |
--positioner-width | The width of the menu’s positioner.
It is important to set width to this value when using CSS to animate size changes. | |
--transform-origin | The coordinates that this element is anchored to. Used for animations and transitions. | |
Positioner.State
type ContextMenuPositionerState = {
/** Whether the menu is currently open. */
open: boolean;
/** The side of the anchor the component is placed on. */
side: Side;
/** The alignment of the component relative to the anchor. */
align: Align;
/** Whether the anchor element is hidden. */
anchorHidden: boolean;
/** Whether the component is nested. */
nested: boolean;
/** Whether CSS transitions should be disabled. */
instant: string | undefined;
};Popup
A container for the menu items.
Renders a <div> element.
finalFocusfunction—
false: Do not move focus.true: Move focus based on the default behavior (trigger or previously focused element).RefObject: Move focus to the ref element.function: Called with the interaction type (mouse, touch, pen, or keyboard).
Return an element to focus, true to use the default behavior, or false/undefined to do nothing.boolean | React.RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | void | HTMLElement | null)childrenReact.ReactNode—
React.ReactNodeclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-open-—
-data-closed-—
-data-alignUnion—
'start' | 'center' | 'end'data-instantUnion—
'click' | 'dismiss' | 'group' | 'trigger-change'data-sideUnion—
'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start'data-starting-style-—
-data-ending-style-—
-Attribute | Description | |
|---|---|---|
data-open | Present when the menu is open. | |
data-closed | Present when the menu is closed. | |
data-align | Indicates how the popup is aligned relative to specified side. | |
data-instant | Present if animations should be instant. | |
data-side | Indicates which side the popup is positioned relative to the anchor. | |
data-starting-style | Present when the menu begins animating in. | |
data-ending-style | Present when the menu is animating out. | |
Popup.State
type ContextMenuPopupState = {
/** The transition status of the component. */
transitionStatus: TransitionStatus;
/** The side of the anchor the component is placed on. */
side: Side;
/** The alignment of the component relative to the anchor. */
align: Align;
/** Whether the menu is currently open. */
open: boolean;
/** Whether the component is nested. */
nested: boolean;
/** Whether transitions should be skipped. */
instant: 'dismiss' | 'click' | 'group' | 'trigger-change' | undefined;
};Arrow
Displays an element positioned against the menu anchor.
Renders a <div> element.
classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-open-—
-data-closed-—
-data-uncentered-—
-data-alignUnion—
'start' | 'center' | 'end'data-sideUnion—
'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start'Attribute | Description | |
|---|---|---|
data-open | Present when the menu popup is open. | |
data-closed | Present when the menu popup is closed. | |
data-uncentered | Present when the menu arrow is uncentered. | |
data-align | Indicates how the popup is aligned relative to specified side. | |
data-side | Indicates which side the popup is positioned relative to the anchor. | |
Arrow.State
type ContextMenuArrowState = {
/** Whether the menu is currently open. */
open: boolean;
/** The side of the anchor the component is placed on. */
side: Side;
/** The alignment of the component relative to the anchor. */
align: Align;
/** Whether the arrow cannot be centered on the anchor. */
uncentered: boolean;
};Item
An individual interactive item in the menu.
Renders a <div> element.
labelstring—
stringonClickfunction—
((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)closeOnClickbooleantrue
booleannativeButtonbooleanfalse
<button> element when replacing it
via the render prop.
Set to true if the rendered element is a native button.booleandisabledbooleanfalse
booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-highlighted-—
-data-disabled-—
-Attribute | Description | |
|---|---|---|
data-highlighted | Present when the menu item is highlighted. | |
data-disabled | Present when the menu item is disabled. | |
Item.State
type ContextMenuItemState = {
/** Whether the item should ignore user interaction. */
disabled: boolean;
/** Whether the item is highlighted. */
highlighted: boolean;
};LinkItem
A link in the menu that can be used to navigate to a different page or section.
Renders an <a> element.
labelstring—
stringcloseOnClickbooleanfalse
booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-highlighted-—
-Attribute | Description | |
|---|---|---|
data-highlighted | Present when the link is highlighted. | |
LinkItem.State
type ContextMenuLinkItemState = {
/** Whether the item is highlighted. */
highlighted: boolean;
};SubmenuRoot
Groups all parts of a submenu. Doesn’t render its own HTML element.
defaultOpenbooleanfalse
open prop instead.booleanopenboolean—
booleanonOpenChangefunction—
((open: boolean, eventDetails: ContextMenu.SubmenuRoot.ChangeEventDetails) => void)highlightItemOnHoverbooleantrue
:hover to be differentiated from the :focus (data-highlighted) state.booleanactionsRefReact.RefObject<MenuRoot.Actions | null>—
unmount: Ends the closing phase of the menu after an externally controlled closing animation finishes.
Call preventUnmountOnClose() in onOpenChange first, otherwise the menu completes closing on its own.
Whether it leaves the DOM is decided by keepMounted on the portal.close: Closes the menu imperatively when called.highlightItem: Moves or clears the highlight while the menu is open.
'next' and 'previous' move sequentially through the items and wrap unless loopFocus
is disabled. 'first' and 'last' highlight the first or last item. 'none' clears the
highlight and hands focus back to the popup.
Calling this action does not open the menu. To highlight an item after opening it, call
the action from onOpenChangeComplete when open is true.
Highlight changes requested through this action report the reason 'imperative-action'
to onItemHighlighted.React.RefObject<MenuRoot.Actions | null>closeParentOnEscbooleanfalse
booleanloopFocusbooleantrue
booleanonItemHighlightedfunction—
undefined if no item is highlighted) and details
containing the reason for the change, the event, and the item’s text label.
The reason can be: 'keyboard': the highlight changed due to keyboard navigation.'pointer': the highlight changed due to pointer hovering. The event may be a MouseEvent
rather than a PointerEvent.'imperative-action': the highlight changed via actionsRef's highlightItem.'none': the highlight changed for another reason, such as automatic highlighting while
filtering, the item list changing, or the popup opening or closing.((highlightedItem: HTMLElement | undefined, eventDetails: MenuRoot.HighlightEventDetails) => void)onOpenChangeCompletefunction—
((open: boolean) => void)disabledbooleanfalse
booleanorientationMenuRoot.Orientation'vertical'
MenuRoot.OrientationchildrenReact.ReactNode—
React.ReactNodeSubmenuRoot.State
type ContextMenuSubmenuRootState = {};SubmenuRoot.ChangeEventReason
type ContextMenuSubmenuRootChangeEventReason =
| 'trigger-hover'
| 'trigger-focus'
| 'trigger-press'
| 'outside-press'
| 'focus-out'
| 'list-navigation'
| 'escape-key'
| 'item-press'
| 'close-press'
| 'sibling-open'
| 'cancel-open'
| 'imperative-action'
| 'none';SubmenuRoot.ChangeEventDetails
type ContextMenuSubmenuRootChangeEventDetails = (
| { reason: 'trigger-hover'; event: MouseEvent }
| { reason: 'trigger-focus'; event: FocusEvent }
| { reason: 'trigger-press'; event: MouseEvent | PointerEvent | TouchEvent | KeyboardEvent }
| { reason: 'outside-press'; event: MouseEvent | PointerEvent | TouchEvent }
| { reason: 'focus-out'; event: FocusEvent | KeyboardEvent }
| { reason: 'list-navigation'; event: KeyboardEvent }
| { reason: 'escape-key'; event: KeyboardEvent }
| { reason: 'item-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'close-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'sibling-open'; event: Event }
| { reason: 'cancel-open'; event: MouseEvent }
| { reason: 'imperative-action'; event: Event }
| { reason: 'none'; event: Event }
) & {
/** Cancels Base UI from handling the event. */
cancel: () => void;
/** Allows the event to propagate in cases where Base UI will stop the propagation. */
allowPropagation: () => void;
/** Indicates whether the event has been canceled. */
isCanceled: boolean;
/** Indicates whether the event is allowed to propagate. */
isPropagationAllowed: boolean;
/** The element that triggered the event, if applicable. */
trigger: Element | undefined;
/** Prevents the popup from unmounting until the `unmount` action is called. */
preventUnmountOnClose: () => void;
};SubmenuTrigger
A menu item that opens a submenu.
Renders a <div> element.
labelstring—
stringonClickfunction—
((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)nativeButtonbooleanfalse
<button> element when replacing it
via the render prop.
Set to true if the rendered element is a native button.booleandisabledbooleanfalse
booleanopenOnHoverbooleantrue
booleandelaynumber100
openOnHover prop.numbercloseDelaynumber0
openOnHover prop.numberclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-popup-open-—
-data-highlighted-—
-data-disabled-—
-Attribute | Description | |
|---|---|---|
data-popup-open | Present when the corresponding submenu is open. | |
data-highlighted | Present when the submenu trigger is highlighted. | |
data-disabled | Present when the submenu trigger is disabled. | |
SubmenuTrigger.State
type ContextMenuSubmenuTriggerState = {
/** Whether the component should ignore user interaction. */
disabled: boolean;
/** Whether the item is highlighted. */
highlighted: boolean;
/** Whether the menu is currently open. */
open: boolean;
};Group
Groups related menu items with the corresponding label.
Renders a <div> element.
childrenReact.ReactNode—
React.ReactNodeclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Group.State
type ContextMenuGroupState = {};GroupLabel
An accessible label that is automatically associated with its parent group.
Renders a <div> element.
classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)GroupLabel.State
type ContextMenuGroupLabelState = {};RadioGroup
Groups related radio items.
Renders a <div> element.
defaultValueany—
value prop instead.anyvalueany—
defaultValue prop instead.anyonValueChangefunction—
((value: any, eventDetails: ContextMenu.RadioGroup.ChangeEventDetails) => void)disabledbooleanfalse
booleanchildrenReact.ReactNode—
React.ReactNodeclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)RadioGroup.State
type ContextMenuRadioGroupState = {
/** Whether the component is disabled. */
disabled: boolean;
};RadioGroup.ChangeEventReason
type ContextMenuRadioGroupChangeEventReason =
| 'trigger-hover'
| 'trigger-focus'
| 'trigger-press'
| 'outside-press'
| 'focus-out'
| 'list-navigation'
| 'escape-key'
| 'item-press'
| 'close-press'
| 'sibling-open'
| 'cancel-open'
| 'imperative-action'
| 'none';RadioGroup.ChangeEventDetails
type ContextMenuRadioGroupChangeEventDetails = (
| { reason: 'trigger-hover'; event: MouseEvent }
| { reason: 'trigger-focus'; event: FocusEvent }
| { reason: 'trigger-press'; event: MouseEvent | PointerEvent | TouchEvent | KeyboardEvent }
| { reason: 'outside-press'; event: MouseEvent | PointerEvent | TouchEvent }
| { reason: 'focus-out'; event: FocusEvent | KeyboardEvent }
| { reason: 'list-navigation'; event: KeyboardEvent }
| { reason: 'escape-key'; event: KeyboardEvent }
| { reason: 'item-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'close-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'sibling-open'; event: Event }
| { reason: 'cancel-open'; event: MouseEvent }
| { reason: 'imperative-action'; event: Event }
| { reason: 'none'; event: Event }
) & {
/** Cancels Base UI from handling the event. */
cancel: () => void;
/** Allows the event to propagate in cases where Base UI will stop the propagation. */
allowPropagation: () => void;
/** Indicates whether the event has been canceled. */
isCanceled: boolean;
/** Indicates whether the event is allowed to propagate. */
isPropagationAllowed: boolean;
/** The element that triggered the event, if applicable. */
trigger: Element | undefined;
/** Prevents the popup from unmounting until the `unmount` action is called. */
preventUnmountOnClose: () => void;
};RadioItem
A menu item that works like a radio button in a given group.
Renders a <div> element.
labelstring—
stringvalue\*any—
anyonClickfunction—
((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)closeOnClickbooleanfalse
booleannativeButtonbooleanfalse
<button> element when replacing it
via the render prop.
Set to true if the rendered element is a native button.booleandisabledbooleanfalse
booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-checked-—
-data-unchecked-—
-data-highlighted-—
-data-disabled-—
-Attribute | Description | |
|---|---|---|
data-checked | Present when the menu radio item is selected. | |
data-unchecked | Present when the menu radio item is not selected. | |
data-highlighted | Present when the menu radio item is highlighted. | |
data-disabled | Present when the menu radio item is disabled. | |
RadioItem.State
type ContextMenuRadioItemState = {
/** Whether the radio item should ignore user interaction. */
disabled: boolean;
/** Whether the radio item is currently highlighted. */
highlighted: boolean;
/** Whether the radio item is currently selected. */
checked: boolean;
};RadioItemIndicator
Indicates whether the radio item is selected.
Renders a <span> element.
classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)keepMountedbooleanfalse
booleanrenderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-checked-—
-data-unchecked-—
-data-disabled-—
-data-starting-style-—
-data-ending-style-—
-Attribute | Description | |
|---|---|---|
data-checked | Present when the menu radio item is selected. | |
data-unchecked | Present when the menu radio item is not selected. | |
data-disabled | Present when the menu radio item is disabled. | |
data-starting-style | Present when the radio indicator begins animating in. | |
data-ending-style | Present when the radio indicator is animating out. | |
RadioItemIndicator.State
type ContextMenuRadioItemIndicatorState = {
/** Whether the radio item is currently selected. */
checked: boolean;
/** Whether the component should ignore user interaction. */
disabled: boolean;
/** Whether the item is highlighted. */
highlighted: boolean;
/** The transition status of the component. */
transitionStatus: TransitionStatus;
};CheckboxItem
A menu item that toggles a setting on or off.
Renders a <div> element.
labelstring—
stringdefaultCheckedbooleanfalse
checked prop instead.booleancheckedboolean—
defaultChecked prop instead.booleanonCheckedChangefunction—
((checked: boolean, eventDetails: ContextMenu.CheckboxItem.ChangeEventDetails) => void)onClickfunction—
((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)closeOnClickbooleanfalse
booleannativeButtonbooleanfalse
<button> element when replacing it
via the render prop.
Set to true if the rendered element is a native button.booleandisabledbooleanfalse
booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-checked-—
-data-unchecked-—
-data-highlighted-—
-data-disabled-—
-Attribute | Description | |
|---|---|---|
data-checked | Present when the menu checkbox item is checked. | |
data-unchecked | Present when the menu checkbox item is not checked. | |
data-highlighted | Present when the menu checkbox item is highlighted. | |
data-disabled | Present when the menu checkbox item is disabled. | |
CheckboxItem.State
type ContextMenuCheckboxItemState = {
/** Whether the checkbox item should ignore user interaction. */
disabled: boolean;
/** Whether the checkbox item is currently highlighted. */
highlighted: boolean;
/** Whether the checkbox item is currently ticked. */
checked: boolean;
};CheckboxItem.ChangeEventReason
type ContextMenuCheckboxItemChangeEventReason =
| 'trigger-hover'
| 'trigger-focus'
| 'trigger-press'
| 'outside-press'
| 'focus-out'
| 'list-navigation'
| 'escape-key'
| 'item-press'
| 'close-press'
| 'sibling-open'
| 'cancel-open'
| 'imperative-action'
| 'none';CheckboxItem.ChangeEventDetails
type ContextMenuCheckboxItemChangeEventDetails = (
| { reason: 'trigger-hover'; event: MouseEvent }
| { reason: 'trigger-focus'; event: FocusEvent }
| { reason: 'trigger-press'; event: MouseEvent | PointerEvent | TouchEvent | KeyboardEvent }
| { reason: 'outside-press'; event: MouseEvent | PointerEvent | TouchEvent }
| { reason: 'focus-out'; event: FocusEvent | KeyboardEvent }
| { reason: 'list-navigation'; event: KeyboardEvent }
| { reason: 'escape-key'; event: KeyboardEvent }
| { reason: 'item-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'close-press'; event: MouseEvent | PointerEvent | KeyboardEvent }
| { reason: 'sibling-open'; event: Event }
| { reason: 'cancel-open'; event: MouseEvent }
| { reason: 'imperative-action'; event: Event }
| { reason: 'none'; event: Event }
) & {
/** Cancels Base UI from handling the event. */
cancel: () => void;
/** Allows the event to propagate in cases where Base UI will stop the propagation. */
allowPropagation: () => void;
/** Indicates whether the event has been canceled. */
isCanceled: boolean;
/** Indicates whether the event is allowed to propagate. */
isPropagationAllowed: boolean;
/** The element that triggered the event, if applicable. */
trigger: Element | undefined;
/** Prevents the popup from unmounting until the `unmount` action is called. */
preventUnmountOnClose: () => void;
};CheckboxItemIndicator
Indicates whether the checkbox item is ticked.
Renders a <span> element.
classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)keepMountedbooleanfalse
booleanrenderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-checked-—
-data-unchecked-—
-data-disabled-—
-data-starting-style-—
-data-ending-style-—
-Attribute | Description | |
|---|---|---|
data-checked | Present when the menu checkbox item is checked. | |
data-unchecked | Present when the menu checkbox item is not checked. | |
data-disabled | Present when the menu checkbox item is disabled. | |
data-starting-style | Present when the indicator begins animating in. | |
data-ending-style | Present when the indicator is animating out. | |
CheckboxItemIndicator.State
type ContextMenuCheckboxItemIndicatorState = {
/** Whether the checkbox item is currently ticked. */
checked: boolean;
/** Whether the component should ignore user interaction. */
disabled: boolean;
/** Whether the item is highlighted. */
highlighted: boolean;
/** The transition status of the component. */
transitionStatus: TransitionStatus;
};Separator
A separator element accessible to screen readers.
Renders a <div> element.
orientationOrientation'horizontal'
Orientationclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-orientationUnion—
'horizontal' | 'vertical'Attribute | Description | |
|---|---|---|
data-orientation | Indicates the orientation of the separator. | |
Separator.State
type ContextMenuSeparatorState = {
/** The orientation of the separator. */
orientation: Orientation;
};