Context Menu

Right-click (or long-press on touch) menu anchored to the trigger region. Same item vocabulary as DropdownMenu.

Right-click (or long-press) here

Installation

pnpm
pnpm dlx @hex-core/cli add context-menu

Row-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

tsx
<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

tsx
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

PropTypeDefaultDescription
onOpenChange
functionCallback on open change
modal
booleantrueWhen 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