Skip to content

ContextMenu

Right-click (or touch long-press) context menu for contextual actions on a region.

<ContextMenu
items={[
{icon: Pencil, label: 'Rename'},
{icon: Copy, label: 'Duplicate'},
{type: 'divider'},
{icon: Trash, label: 'Delete'},
]}>
<div className={styles.target}>
<Text as="span" type="body">
Right-click this area
</Text>
</div>
</ContextMenu>
<ContextMenu
items={[
{icon: Pencil, label: 'Rename'},
{icon: Copy, label: 'Duplicate'},
{type: 'divider'},
{icon: Trash, label: 'Delete'},
]}>
<div className={styles.target}>
<Text as="span" type="body">
Long-press this area on a touch device (or right-click)
</Text>
</div>
</ContextMenu>
<ContextMenu
items={[
{
description: 'Change the file name',
icon: Pencil,
label: 'Rename',
},
{
description: 'Create an identical copy',
icon: Copy,
label: 'Duplicate',
},
{type: 'divider'},
{
description: 'Move to trash',
icon: Trash,
label: 'Delete',
},
]}>
<div className={styles.target}>
<Text as="span" type="body">
Right-click for actions with descriptions
</Text>
</div>
</ContextMenu>
<ContextMenu
menuContent={
<>
<ContextMenuItem
endContent={<Kbd keys="mod+r" />}
icon={Pencil}
label="Rename"
/>
<ContextMenuItem
endContent={<Kbd keys="mod+d" />}
icon={Copy}
label="Duplicate"
/>
<Divider />
<ContextMenuItem
endContent={<Kbd keys="backspace" />}
icon={Trash}
label="Delete"
/>
</>
}>
<div className={styles.target}>
<Text as="span" type="body">
Right-click for actions with shortcuts
</Text>
</div>
</ContextMenu>
<ContextMenu
items={[
{icon: Pencil, label: 'Rename'},
{icon: Copy, isDisabled: true, label: 'Duplicate'},
{type: 'divider'},
{icon: Trash, isDisabled: true, label: 'Delete'},
]}>
<div className={styles.target}>
<Text as="span" type="body">
Right-click — some actions disabled
</Text>
</div>
</ContextMenu>
<ContextMenu
isDisabled
items={[
{icon: Pencil, label: 'Rename'},
{icon: Copy, label: 'Duplicate'},
]}>
<div className={styles.target}>
<Text as="span" type="body">
Right-click falls through to browser menu
</Text>
</div>
</ContextMenu>
(): React.JSX.Element => {
const items = [
{icon: Pencil, label: 'Rename'},
{icon: Copy, label: 'Duplicate'},
{type: 'divider' as const},
{icon: Trash, label: 'Delete'},
];
return (
<div style={{display: 'flex', gap: '2rem'}}>
<ContextMenu items={items} size="sm">
<div className={styles.target}>
<Text as="span" type="body">
Small
</Text>
</div>
</ContextMenu>
<ContextMenu items={items} size="md">
<div className={styles.target}>
<Text as="span" type="body">
Medium
</Text>
</div>
</ContextMenu>
<ContextMenu items={items} size="lg">
<div className={styles.target}>
<Text as="span" type="body">
Large
</Text>
</div>
</ContextMenu>
</div>
);
}
<ContextMenu
items={[
{
items: [
{icon: Pencil, label: 'Rename'},
{icon: Copy, label: 'Duplicate'},
],
title: 'Edit',
type: 'section',
},
{
items: [{icon: Download, label: 'Export'}],
title: 'Share',
type: 'section',
},
]}>
<div className={styles.target}>
<Text as="span" type="body">
Right-click for grouped actions
</Text>
</div>
</ContextMenu>
Scroll to the bottom-right target and right-click it. Scrolling this region again dismisses the menu. If left open, the menu grows after a moment so its edge flipping can be checked at narrow canvas sizes.
Scroll down and right
function PositioningAndScrollExample(): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<div className={styles.positioningExample}>
<Text color="secondary" type="supporting">
Scroll to the bottom-right target and right-click it. Scrolling this
region again dismisses the menu. If left open, the menu grows after a
moment so its edge flipping can be checked at narrow canvas sizes.
</Text>
<div className={styles.scrollRegion}>
<div className={styles.scrollContent}>
<Text color="secondary" type="supporting">
Scroll down and right
</Text>
<div className={styles.edgeTarget}>
<ContextMenu
menuContent={
isOpen ? (
<GrowingMenuContent />
) : (
<ContextMenuItem icon={Pencil} label="Rename" />
)
}
onOpenChange={setIsOpen}>
<div className={styles.target}>
<Text as="span" type="body">
Right-click near the edge
</Text>
</div>
</ContextMenu>
</div>
</div>
</div>
</div>
);
}
function GrowingMenuContent(): React.JSX.Element {
const [hasGrown, setHasGrown] = useState(false);
useEffect(() => {
const timeout = setTimeout(() => setHasGrown(true), 800);
return () => clearTimeout(timeout);
}, []);
return (
<>
<ContextMenuItem icon={Pencil} label="Rename" />
<ContextMenuItem icon={Copy} label="Duplicate" />
{hasGrown ? (
<>
<Divider />
<ContextMenuItem label="Move to project" />
<ContextMenuItem label="Share link" />
<ContextMenuItem icon={Download} label="Export archive" />
<ContextMenuItem icon={Trash} label="Delete" />
</>
) : null}
</>
);
}
<PositioningAndScrollExample />
<ContextMenu
items={[
{icon: Pencil, label: 'Edit'},
{icon: Copy, label: 'Duplicate'},
{type: 'divider'},
{icon: Trash, label: 'Delete'},
]}>
<Card style={{width: 360}}>
<LayoutHeader
endContent={<Badge color="blue" label="Active" />}
title="Project Alpha"
/>
<LayoutContent>
<Text color="secondary" type="supporting">
3 members · Last updated 2 hours ago. Right-click for options.
</Text>
</LayoutContent>
</Card>
</ContextMenu>

Right-click (or touch long-press) context menu for contextual actions on a region.

When Variant 1

PropTypeDefaultDescription
items*ReadonlyArray<ContextMenuOption>—
menuContentnever—
children*ReactNode—The region that triggers the context menu on right-click or touch long-press.
classNamestring—Additional CSS class names applied to the menu surface.
data-testidstring—Test ID applied to the trigger wrapper.
hasAutoFocusbooleantrueWhether to auto-focus the first menu item on open.
isDisabledbooleanfalseWhether the context menu is disabled.
menuWidthnumber | string160Width of the menu surface.
onOpenChange(isOpen: boolean) => void—Called when the menu open state changes.
refRef<HTMLDivElement>—Ref forwarded to the trigger wrapper.
size"sm" | "md" | "lg"'md'Menu item size.
styleCSSProperties—Inline styles applied to the menu surface.

When Variant 2

PropTypeDefaultDescription
itemsnever—
menuContent*ReactNode—
children*ReactNode—The region that triggers the context menu on right-click or touch long-press.
classNamestring—Additional CSS class names applied to the menu surface.
data-testidstring—Test ID applied to the trigger wrapper.
hasAutoFocusbooleantrueWhether to auto-focus the first menu item on open.
isDisabledbooleanfalseWhether the context menu is disabled.
menuWidthnumber | string160Width of the menu surface.
onOpenChange(isOpen: boolean) => void—Called when the menu open state changes.
refRef<HTMLDivElement>—Ref forwarded to the trigger wrapper.
size"sm" | "md" | "lg"'md'Menu item size.
styleCSSProperties—Inline styles applied to the menu surface.
PropTypeDefaultDescription
aria-keyshortcutsAriaAttributes['aria-keyshortcuts']—Keyboard shortcuts that activate the menu item.
classNamestring—Additional CSS class names applied to the item.
data-testidstring—Test ID applied to the item.
descriptionReactNode—Supporting text shown below the label.
endContentReactNode—Trailing content.
hasCloseOnSelectbooleantrueWhether activating the item closes the menu. Set to false for items users flip repeatedly, such as toggles, so the menu stays open with focus on the item.
iconIconComponent—Icon rendered before the label.
isDisabledbooleanfalseWhether the item is disabled.
label*string—Item label.
onClick() => void—Called when the item is selected.
refRef<HTMLButtonElement>—Ref forwarded to the item button.
styleCSSProperties—Inline styles applied to the item.
tooltipReactNode—Tooltip content shown when the item is hovered or focused.