Context Menu
A menu of actions that opens at the pointer on right click or long press.
Rows take variant for their look — neutral (the default) and danger for a destructive action.
Show codeHide code
Installation
import {
ContextMenu,
ContextMenuTrigger,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
} from "@makeplane/propel/components/context-menu";Usage
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuTrigger,
} from "@makeplane/propel/components/context-menu";
import { Icon } from "@makeplane/propel/components/icon";
import { Shortcut } from "@makeplane/propel/components/shortcut";
import { ClipboardOutline, CopyOutline, UndoOutline, DeleteOutline } from "@makeplane/propel/icons";
const triggerClass =
"flex h-32 w-72 items-center justify-center rounded-lg border-sm border-dashed border-subtle text-body-xs-regular text-tertiary select-none";
export default function BasicDemo() {
return (
<ContextMenu>
<ContextMenuTrigger render={<div className={triggerClass} />}>
Right-click here
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
icon={<Icon icon={UndoOutline} />}
aria-keyshortcuts="Meta+Z"
trailing={<Shortcut keys="⌘Z" />}
label="Undo"
/>
<ContextMenuItem
icon={<Icon icon={CopyOutline} />}
aria-keyshortcuts="Meta+C"
trailing={<Shortcut keys="⌘C" />}
label="Copy"
/>
<ContextMenuItem
icon={<Icon icon={ClipboardOutline} />}
aria-keyshortcuts="Meta+V"
trailing={<Shortcut keys="⌘V" />}
label="Paste"
/>
<ContextMenuSeparator />
<ContextMenuItem variant="danger" icon={<Icon icon={DeleteOutline} />} label="Delete" />
</ContextMenuContent>
</ContextMenu>
);
}Examples
Submenu
Nest a ContextMenuSubmenu to reveal more destinations beside the parent menu.
Root and submenu both size themselves auto: as wide as their rows, between the 204px floor and
the 400px ceiling. The rule is on the Sizing page.
Show codeHide code
Link items
ContextMenuLinkItem renders a real anchor, so a row can navigate while keeping menu-item behavior.
Pass external for outbound links (target="_blank", rel="noreferrer noopener", trailing arrow).
Show codeHide code
Selection rows
ContextMenuCheckboxItem toggles independently; ContextMenuRadioItem rows wrapped in a
ContextMenuRadioGroup share one value. Both pass closeOnClick={false} so the menu stays open
while you adjust the options. The radio group passes marker="radio" because this popup also holds a
checkbox row: next to a box, the default trailing tick would make the two kinds of choice read the
same. A single-select group on its own keeps the default tick and no leading gutter.
Show codeHide code
Single select
A selected row shows a trailing check at the row’s inline-end; forwarding closeOnClick={false} moves the check without dismissing the menu. Pass selected on every row of a single-select list so unselected rows keep the trailing gutter and the labels hold a common width.
Show codeHide code
With description
A description gives each row a muted second line; passing it switches the row to a taller, top-aligned layout, so the icon and check line up with the label.
Show codeHide code
API Reference
ContextMenu
Root of the context menu: holds the open state and the pointer position the menu anchors to, and
renders no element of its own. Wrap a ContextMenuTrigger and a ContextMenuContent in it; the
menu opens on right click or long press anywhere inside the trigger.
ContextMenuTrigger
The behavior surface that opens the menu on right click or long press — Base UI applies no
styling of its own, so give it a look by grafting it onto your own element via render:
``tsx
<ContextMenuTrigger render={<MyCanvasArea />}>Right-click here</ContextMenuTrigger>;
Maps 1:1 to ContextMenu.Trigger`.
ContextMenuContent
The root context-menu surface: Base UI's portal and positioner wrapped around an elevated,
scrollable OverlayPanel holding the flat role="menu" popup. Anchors to the pointer and sizes
itself like a dropdown. Rows (ContextMenuItem, ContextMenuSeparator, …) are its children. A
submenu's own surface is ContextMenuSubmenuContent, not this part.
ContextMenuItem
The ready-made menu row: grafts Base UI's Item behavior onto the styled ContextMenuItem and
composes its region parts — an optional leading icon, the label and an optional description, the
single-select check, and optional trailing content.
ContextMenuCheckboxItem
The ready-made toggleable context-menu row: grafts Base UI's CheckboxItem behavior onto the
styled row and bakes a kept-mounted tick indicator, so checked / defaultChecked /
onCheckedChange forward straight to Base UI and the tick reads state from context.
ContextMenuRadioGroup
Wraps ContextMenuRadioItems sharing one value — Base UI's radio-group state, no chrome.
ContextMenuRadioItem
The ready-made single-select context-menu row: grafts Base UI's RadioItem behavior onto the
styled row and marks the current row the way its ContextMenuRadioGroup's marker says. check
(the default): a kept-mounted trailing tick on the selected row. radio: a leading ring drawn on
every row with only its inner dot hiding, for a popup that also holds a checkbox group. Wrap rows
in a ContextMenuRadioGroup carrying value/onValueChange; both the selected state and the
marker come from context.
ContextMenuLinkItem
The ready-made navigational menu row: grafts Base UI's LinkItem behavior onto the styled
ContextMenuLinkItem and composes its region parts — a leading icon, the label, and optional
trailing content.
ContextMenuGroup
Groups related rows; provide aria-label/aria-labelledby when the group needs a name.
ContextMenuSeparator
Ready-made divider between groups of items: Base UI's ContextMenu.Separator behavior (the
separator role) grafted onto the styled thin rule.
ContextMenuSubmenu
Groups all parts of a nested submenu — its ContextMenuSubmenuTrigger row and the
ContextMenuSubmenuContent that opens beside it. Holds the submenu's own open state and renders
no element of its own.
ContextMenuSubmenuTrigger
The ready-made submenu trigger: grafts Base UI's SubmenuTrigger behavior onto the styled
ContextMenuSubmenuTrigger and composes its region parts — a leading icon, the label, optional
trailing content, and the caret that points toward the submenu.