Context Menu
Right-click (or long-press on touch) menu anchored to the trigger region. Same item vocabulary as DropdownMenu.
Installation
pnpm dlx @hex-core/cli add context-menuRow-level actions on a data row
Right-click a table row to copy, pin, or delete it. The trigger spans the whole row via asChild on a <tr>; ContextMenuLabel surfaces the row's identity at the top of the menu
<ContextMenu>
<ContextMenuTrigger asChild>
<tr className="cursor-context-menu hover:bg-muted/40">
<td className="px-3 py-2">{invoice.id}</td>
<td className="px-3 py-2">{invoice.customer}</td>
<td className="px-3 py-2 text-right">{invoice.amount}</td>
</tr>
</ContextMenuTrigger>
<ContextMenuContent className="w-56">
<ContextMenuLabel>{invoice.id}</ContextMenuLabel>
<ContextMenuSeparator />
<ContextMenuItem onSelect={() => copyId(invoice.id)}>
Copy invoice ID
<ContextMenuShortcut>⌘C</ContextMenuShortcut>
</ContextMenuItem>
<ContextMenuItem onSelect={() => pinRow(invoice.id)}>Pin to top</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem className="text-destructive" onSelect={() => deleteInvoice(invoice.id)}>
Delete…
<ContextMenuShortcut>⌫</ContextMenuShortcut>
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>View prefs with checkbox + radio items
Editor-style context menu mixing ContextMenuCheckboxItem (toggleable view options) with a ContextMenuRadioGroup for a single-pick theme value
const [showLineNumbers, setShowLineNumbers] = useState(true);
const [wordWrap, setWordWrap] = useState(false);
const [theme, setTheme] = useState("system");
return (
<ContextMenu>
<ContextMenuTrigger className="flex h-40 items-center justify-center rounded-md border border-dashed">
Right-click the editor
</ContextMenuTrigger>
<ContextMenuContent className="w-56">
<ContextMenuLabel>View</ContextMenuLabel>
<ContextMenuCheckboxItem checked={showLineNumbers} onCheckedChange={setShowLineNumbers}>
Show line numbers
</ContextMenuCheckboxItem>
<ContextMenuCheckboxItem checked={wordWrap} onCheckedChange={setWordWrap}>
Word wrap
</ContextMenuCheckboxItem>
<ContextMenuSeparator />
<ContextMenuLabel>Theme</ContextMenuLabel>
<ContextMenuRadioGroup value={theme} onValueChange={setTheme}>
<ContextMenuRadioItem value="light">Light</ContextMenuRadioItem>
<ContextMenuRadioItem value="dark">Dark</ContextMenuRadioItem>
<ContextMenuRadioItem value="system">System</ContextMenuRadioItem>
</ContextMenuRadioGroup>
</ContextMenuContent>
</ContextMenu>
);API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
onOpenChange | function | — | Callback on open change |
modal | boolean | true | When true, interaction outside is blocked |
dir | "ltr" | "rtl" | — | Reading direction |
AI Guidance
When to use
Use for right-click menus on a specific region: file-manager-style actions, canvas/editor context actions, row-level actions in tables.
When not to use
Don't use for actions triggered by a button (use DropdownMenu). Don't use as the only way to access an action — must have a keyboard/button alternative.
Common mistakes
- Using ContextMenu as the only affordance (unreachable on touch)
- Triggering on the whole document (put it on a specific region)
- Missing a keyboard alternative for items
Accessibility
Triggered via right-click or Shift+F10 on keyboard. Radix handles role='menu', aria-labelledby, focus management.
Related components
Token budget: 700
Verified against @hex-core/components@1.12.0