Displays a menu located at the pointer, triggered by a right-click or a long-press.
Supports submenus with configurable reading direction.
Supports items, labels, groups of items.
Supports checkable items (single or multiple) with optional indeterminate state.
Supports modal and non-modal modes.
Customize side, alignment, offsets, collision handling.
Focus is fully managed.
Full keyboard navigation.
Typeahead support.
Dismissing and layering behavior is highly customizable.
Triggers with a long-press on touch devices
Install the component from your command line.
npm install @radix-ui/react-context-menu
Import all parts and piece them together.
import * as ContextMenu from '@radix-ui/react-context-menu';
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger />
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Label />
<ContextMenu.Item />
<ContextMenu.Group>
<ContextMenu.Item />
</ContextMenu.Group>
<ContextMenu.CheckboxItem>
<ContextMenu.ItemIndicator />
</ContextMenu.CheckboxItem>
<ContextMenu.RadioGroup>
<ContextMenu.RadioItem>
<ContextMenu.ItemIndicator />
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
<ContextMenu.Sub>
<ContextMenu.SubTrigger />
<ContextMenu.Portal>
<ContextMenu.SubContent />
</ContextMenu.Portal>
</ContextMenu.Sub>
<ContextMenu.Separator />
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
Adheres to the Menu WAI-ARIA design pattern and uses roving tabindex to manage focus movement among menu items.
Contains all the parts of a context menu.
The area that opens the context menu. Wrap it around the target you want the context menu to open from when right-clicking (or using the relevant keyboard shortcuts).
When used, portals the content part into the body
.
The component that pops out in an open context menu.
An optional arrow element to render alongside a submenu. This can be used to help visually link the trigger item with the ContextMenu.Content
. Must be rendered inside ContextMenu.Content
.
The component that contains the context menu items.
Used to group multiple ContextMenu.Item
s.
Used to render a label. It won't be focusable using arrow keys.
An item that can be controlled and rendered like a checkbox.
Used to group multiple ContextMenu.RadioItem
s.
An item that can be controlled and rendered like a radio.
Renders when the parent ContextMenu.CheckboxItem
or ContextMenu.RadioItem
is checked. You can style this element directly, or you can use it as a wrapper to put an icon into, or both.
Used to visually separate items in the context menu.
Contains all the parts of a submenu.
An item that opens a submenu. Must be rendered inside ContextMenu.Sub
.
The component that pops out when a submenu is open. Must be rendered inside ContextMenu.Sub
.
You can create submenus by using ContextMenu.Sub
in combination with its parts.
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger>Sub menu →</ContextMenu.SubTrigger>
<ContextMenu.Portal>
<ContextMenu.SubContent>
<ContextMenu.Item>Sub menu item</ContextMenu.Item>
<ContextMenu.Item>Sub menu item</ContextMenu.Item>
<ContextMenu.Arrow />
</ContextMenu.SubContent>
</ContextMenu.Portal>
</ContextMenu.Sub>
<ContextMenu.Separator />
<ContextMenu.Item>…</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
You can add special styles to disabled items via the data-disabled
attribute.
// index.jsx
import * as ContextMenu from '@radix-ui/react-context-menu';
import './styles.css';
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item className="ContextMenuItem" disabled>
…
</ContextMenu.Item>
<ContextMenu.Item className="ContextMenuItem">…</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuItem[data-disabled] {
color: gainsboro;
}
Use the Separator
part to add a separator between items.
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item>…</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
Use the Label
part to help label a section.
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Label>Label</ContextMenu.Label>
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Item>…</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
Use the CheckboxItem
part to add an item that can be checked.
import React from 'react';
import { CheckIcon } from '@radix-ui/react-icons';
import * as ContextMenu from '@radix-ui/react-context-menu';
export default () => {
const [checked, setChecked] = React.useState(true);
return (
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Item>…</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.CheckboxItem
checked={checked}
onCheckedChange={setChecked}
>
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
Checkbox item
</ContextMenu.CheckboxItem>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
};
Use the RadioGroup
and RadioItem
parts to add an item that can be checked amongst others.
import React from 'react';
import { CheckIcon } from '@radix-ui/react-icons';
import * as ContextMenu from '@radix-ui/react-context-menu';
export default () => {
const [color, setColor] = React.useState('blue');
return (
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.RadioGroup value={color} onValueChange={setColor}>
<ContextMenu.RadioItem value="red">
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
Red
</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="blue">
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
Blue
</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="green">
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
Green
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
};
You can add extra decorative elements in the Item
parts, such as images.
import * as ContextMenu from '@radix-ui/react-context-menu';
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item>
<img src="…" />
Adolfo Hess
</ContextMenu.Item>
<ContextMenu.Item>
<img src="…" />
Miyah Myles
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
You may want to constrain the width of the content (or sub-content) so that it matches the trigger (or sub-trigger) width. You may also want to constrain its height to not exceed the viewport.
We expose several CSS custom properties such as --radix-context-menu-trigger-width
and --radix-context-menu-content-available-height
to support this. Use them to constrain the content dimensions.
// index.jsx
import * as ContextMenu from '@radix-ui/react-context-menu';
import './styles.css';
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="ContextMenuContent">
…
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuContent {
width: var(--radix-context-menu-trigger-width);
max-height: var(--radix-context-menu-content-available-height);
}
We expose a CSS custom property --radix-context-menu-content-transform-origin
. Use it to animate the content from its computed origin based on side
, sideOffset
, align
, alignOffset
and any collisions.
// index.jsx
import * as ContextMenu from '@radix-ui/react-context-menu';
import './styles.css';
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="ContextMenuContent">
…
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuContent {
transform-origin: var(--radix-context-menu-content-transform-origin);
animation: scaleIn 0.5s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}
We expose data-side
and data-align
attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations.
// index.jsx
import * as ContextMenu from '@radix-ui/react-context-menu';
import './styles.css';
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger>…</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="ContextMenuContent">
…
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuContent {
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.ContextMenuContent[data-side='top'] {
animation-name: slideUp;
}
.ContextMenuContent[data-side='bottom'] {
animation-name: slideDown;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Uses roving tabindex to manage focus movement among menu items.