Context Menu A right-click context menu with sub-menus, checkbox items, radio groups, and keyboard shortcuts. Built on Radix UI.
ContextMenu is a right-click (or long-press) triggered menu built on Radix UI's ContextMenu primitive. It supports nested submenus, checkbox items, radio groups, keyboard shortcuts, and full keyboard navigation.
Install the component via the CLI in one command.
npm pnpm yarn bun
npx @work-rjkashyap/unified-ui add context-menu pnpm dlx @work-rjkashyap/unified-ui add context-menu npx @work-rjkashyap/unified-ui add context-menu bunx @work-rjkashyap/unified-ui add context-menu
If you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for details.
Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.
npm pnpm yarn bun
npm install @work-rjkashyap/unified-ui pnpm add @work-rjkashyap/unified-ui yarn add @work-rjkashyap/unified-ui bun add @work-rjkashyap/unified-ui
import {
ContextMenu,
ContextMenuTrigger,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuLabel,
ContextMenuShortcut,
ContextMenuSub,
ContextMenuSubTrigger,
ContextMenuSubContent,
ContextMenuCheckboxItem,
ContextMenuRadioGroup,
ContextMenuRadioItem,
ContextMenuGroup,
} from "@work-rjkashyap/unified-ui" ;
<ContextMenu> <ContextMenuTrigger> <div className="flex h-28 w-64 items-center justify-center rounded-md border-2 border-dashed border-border text-sm text-muted-foreground"> Right-click here </div> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuItem> Open <ContextMenuShortcut>↵</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem>Open in New Tab</ContextMenuItem> <ContextMenuItem>Copy Link</ContextMenuItem> <ContextMenuSeparator /> <ContextMenuItem variant="danger">Delete</ContextMenuItem> </ContextMenuContent> </ContextMenu>
<ContextMenu> <ContextMenuTrigger> <div className="...">Right-click here</div> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuLabel>File</ContextMenuLabel> <ContextMenuGroup> <ContextMenuItem> New File <ContextMenuShortcut>⌘N</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Open <ContextMenuShortcut>⌘O</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Save <ContextMenuShortcut>⌘S</ContextMenuShortcut> </ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuLabel>Edit</ContextMenuLabel> <ContextMenuGroup> <ContextMenuItem>Cut <ContextMenuShortcut>⌘X</ContextMenuShortcut></ContextMenuItem> <ContextMenuItem>Copy <ContextMenuShortcut>⌘C</ContextMenuShortcut></ContextMenuItem> <ContextMenuItem>Paste <ContextMenuShortcut>⌘V</ContextMenuShortcut></ContextMenuItem> </ContextMenuGroup> </ContextMenuContent> </ContextMenu>
<ContextMenu> <ContextMenuTrigger> <div>Right-click here</div> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuItem>Back</ContextMenuItem> <ContextMenuItem>Forward</ContextMenuItem> <ContextMenuItem>Reload</ContextMenuItem> <ContextMenuSeparator /> <ContextMenuSub> <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger> <ContextMenuSubContent> <ContextMenuItem>Save Page As...</ContextMenuItem> <ContextMenuItem>Create Shortcut...</ContextMenuItem> <ContextMenuSeparator /> <ContextMenuItem>Developer Tools</ContextMenuItem> </ContextMenuSubContent> </ContextMenuSub> <ContextMenuSeparator /> <ContextMenuItem variant="danger">Delete</ContextMenuItem> </ContextMenuContent> </ContextMenu>
const [showStatusBar, setShowStatusBar] = useState(true); const [showActivityBar, setShowActivityBar] = useState(false); const [showPanel, setShowPanel] = useState(false); <ContextMenu> <ContextMenuTrigger> <div>Right-click here</div> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuLabel>Panels</ContextMenuLabel> <ContextMenuCheckboxItem checked={showStatusBar} onCheckedChange={setShowStatusBar} > Status Bar </ContextMenuCheckboxItem> <ContextMenuCheckboxItem checked={showActivityBar} onCheckedChange={setShowActivityBar} > Activity Bar </ContextMenuCheckboxItem> <ContextMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel} > Panel </ContextMenuCheckboxItem> </ContextMenuContent> </ContextMenu>
const [view, setView] = useState("list"); <ContextMenu> <ContextMenuTrigger> <div>Right-click here</div> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuLabel>View</ContextMenuLabel> <ContextMenuRadioGroup value={view} onValueChange={setView}> <ContextMenuRadioItem value="list">List</ContextMenuRadioItem> <ContextMenuRadioItem value="grid">Grid</ContextMenuRadioItem> <ContextMenuRadioItem value="columns">Columns</ContextMenuRadioItem> </ContextMenuRadioGroup> </ContextMenuContent> </ContextMenu>
<ContextMenu> <ContextMenuTrigger> <div>Right-click here</div> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuItem>Edit</ContextMenuItem> <ContextMenuItem>Duplicate</ContextMenuItem> <ContextMenuItem>Archive</ContextMenuItem> <ContextMenuSeparator /> <ContextMenuItem variant="danger"> Remove <ContextMenuShortcut>⌫</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem variant="danger"> Delete Permanently <ContextMenuShortcut>⌘⌫</ContextMenuShortcut> </ContextMenuItem> </ContextMenuContent> </ContextMenu>
Prop Type Default Description openboolean— Controlled open state. onOpenChange(open: boolean) => void— Callback when open state changes. modalbooleantrueWhether the menu is modal. dir"ltr" | "rtl"— Reading direction for submenus. childrenReactNode— Required. Must include Trigger and Content.
Prop Type Default Description asChildbooleanfalseRender as the child element instead of a <span>. disabledbooleanfalseDisables the right-click trigger. classNamestring— Additional CSS classes.
Prop Type Default Description loopbooleanfalseWhether keyboard navigation loops. alignOffsetnumber0Offset from the alignment edge. collisionPaddingnumber8Padding from viewport edges. classNamestring— Additional CSS classes.
Prop Type Default Description variant"default" | "danger""default"Visual variant of the item. iconReactNode— Icon rendered before the label. disabledbooleanfalseDisables the item. onSelect(e: Event) => void— Callback when the item is selected. classNamestring— Additional CSS classes.
Prop Type Default Description checkedboolean— Whether the checkbox is checked. onCheckedChange(checked: boolean) => void— Callback when the checked state changes. disabledbooleanfalseDisables the item. classNamestring— Additional CSS classes.
Prop Type Default Description valuestring— The controlled selected value. onValueChange(value: string) => void— Callback when the selected value changes. classNamestring— Additional CSS classes.
Prop Type Default Description valuestring— Required. The value of this item. disabledbooleanfalseDisables the item. classNamestring— Additional CSS classes.
Prop Type Default Description insetbooleanfalseAdds left padding to align with items that have icons. classNamestring— Additional CSS classes.
Prop Type Default Description insetbooleanfalseAligns the sub-trigger with icon items. iconReactNode— Icon rendered before the sub-trigger label.
< ContextMenu >
< ContextMenuTrigger /> { /* Right-click target */ }
< ContextMenuContent >
{ " " }
{ /* Menu panel */ }
< ContextMenuLabel /> { /* Section heading */ }
< ContextMenuGroup >
{ " " }
{ /* Logical grouping */ }
< ContextMenuItem /> { /* Standard action */ }
< ContextMenuCheckboxItem /> { /* Boolean toggle */ }
</ ContextMenuGroup >
< ContextMenuRadioGroup >
{ " " }
{ /* Exclusive selection */ }
< ContextMenuRadioItem />
</ ContextMenuRadioGroup >
< ContextMenuSeparator /> { /* Visual divider */ }
< ContextMenuSub >
{ " " }
{ /* Nested submenu */ }
< ContextMenuSubTrigger />
< ContextMenuSubContent >
< ContextMenuItem />
</ ContextMenuSubContent >
</ ContextMenuSub >
</ ContextMenuContent >
</ ContextMenu >
Context menus are inaccessible to keyboard-only users if the trigger area
cannot be focused. Ensure your trigger element is keyboard-reachable (or
provide an alternative mechanism).
Right-click / long-press — Opens the menu at the cursor position.
Arrow keys — Navigate between menu items.
Enter / Space — Select the focused item.
Escape — Close the menu.
Tab — Closes the menu and moves focus to the next focusable element.
Submenu navigation — Right arrow opens a submenu; Left arrow closes it.
role="menu" and role="menuitem" are applied automatically by Radix UI.