Right-click or long-press menu that opens at the pointer: it scales from the nearest corner, items stagger in, a highlight glides between rows and submenus slide in beside their item.
context menuright clickmenulong presssubmenushortcutskeyboarddropdown
Installation
$npx shadcn@latest add @geturui/context-menu
Usage
usage.tsx
1import { Copy, Pencil, Trash2 } from "lucide-react";
2import { ContextMenu } from "@/components/ui/context-menu";
3
4export function FileCard() {
5 return (
6 <ContextMenu
7 items={[
8 { label: "Rename", icon: <Pencil />, shortcut: "F2", onSelect: () => {} },
9 { label: "Duplicate", icon: <Copy />, shortcut: "⌘D", onSelect: () => {} },
10 { label: "Share", items: [{ label: "Copy link", onSelect: () => {} }, { label: "Invite people", onSelect: () => {} }] },
11 { type: "separator" },
12 { label: "Move to trash", icon: <Trash2 />, danger: true, onSelect: () => {} },
13 ]}
14 >
15 <div className="rounded-xl border p-6">Right-click me</div>
16 </ContextMenu>
17 );
18}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items* | ContextMenuEntry[] | — | Items { label, icon?, shortcut?, onSelect?, disabled?, danger?, checked?, items? }, { type: "separator" } or { type: "label", label }. Nested items open a submenu. |
children* | ReactNode | — | The area that responds to right-click, long-press and the menu key. |
longPressDelay | number | 500 | Touch and pen long-press duration in ms. |
onOpenChange | (open: boolean) => void | — | Called when the menu opens or closes. |
disabled | boolean | false | Let the browser's native menu through. |
className | string | — | Classes for the target wrapper. |
menuClassName | string | — | Classes for every menu surface, including submenus. |
Accessibility
- role="menu" surfaces with menuitem / menuitemcheckbox rows, aria-disabled, aria-haspopup and aria-expanded on submenu parents; separators use role="separator".
- The target is focusable and opens with the Menu key or Shift+F10. Up and Down move (wrapping), Home and End jump, Right or Enter opens a submenu, Left or Escape closes it, Escape at the root closes and restores focus, Tab closes.
- Opens at the pointer but flips to stay inside the viewport; submenus open on the side with room. Scroll, resize, blur and outside press close it.
- With reduced motion items appear without stagger and surfaces fade without scale or blur.