Context Menu
A right-click context menu with items, checkbox items, radio groups, sub-menus, separators, and labels. Fully keyboard-accessible with ARIA roles.
Installation
npx vayu-ui init #one time onlynpx vayu-ui add contextmenunpx vayu-ui add -t contextmenu #with test case needsUsage
Right-click the area below to open the context menu.
Keyboard shortcuts:
- ↑/↓ arrows to navigate
- → to open submenu
- ← to close submenu
- Type to search items
- Home/End to jump
Current State:
Show Bookmarks: true
Show URLs: false
Assignee: andy
<ContextMenu>
<ContextMenu.Trigger>
<div>Right-click here</div>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Item shortcut="⌘Z" onSelect={() => console.log('Undo')}>
Undo
</ContextMenu.Item>
<ContextMenu.Item shortcut="⌘⇧Z" onSelect={() => console.log('Redo')}>
Redo
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item shortcut="⌘X">Cut</ContextMenu.Item>
<ContextMenu.Item shortcut="⌘C">Copy</ContextMenu.Item>
<ContextMenu.Item shortcut="⌘V">Paste</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger>Export As</ContextMenu.SubTrigger>
<ContextMenu.SubContent>
<ContextMenu.Item>PDF Document</ContextMenu.Item>
<ContextMenu.Item>PNG Image</ContextMenu.Item>
</ContextMenu.SubContent>
</ContextMenu.Sub>
<ContextMenu.Separator />
<ContextMenu.Label>View Options</ContextMenu.Label>
<ContextMenu.CheckboxItem checked={showBookmarks} onCheckedChange={setShowBookmarks}>
Show Bookmarks Bar
</ContextMenu.CheckboxItem>
<ContextMenu.Separator />
<ContextMenu.Label>Assignee</ContextMenu.Label>
<ContextMenu.RadioGroup value={person} onValueChange={setPerson}>
<ContextMenu.RadioItem value="andy">Andy</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="pedro">Pedro</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
<ContextMenu.Separator />
<ContextMenu.Item destructive>Delete</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu>Anatomy
import { ContextMenu } from 'vayu-ui';
export default () => (
<ContextMenu>
<ContextMenu.Trigger>
<div>Right-click target area</div>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Label>Section Label</ContextMenu.Label>
<ContextMenu.Item>Menu Item</ContextMenu.Item>
<ContextMenu.CheckboxItem checked>Checkbox Item</ContextMenu.CheckboxItem>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger>Submenu Trigger</ContextMenu.SubTrigger>
<ContextMenu.SubContent>
<ContextMenu.Item>Sub Item</ContextMenu.Item>
</ContextMenu.SubContent>
</ContextMenu.Sub>
<ContextMenu.RadioGroup value="val">
<ContextMenu.RadioItem value="val">Radio Item</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
</ContextMenu.Content>
</ContextMenu>
);Accessibility
- Keyboard support: Right-click,
Context Menukey, orShift+F10opens the menu.ArrowUp/ArrowDownnavigates items.EnterorSpaceselects an item.Escapecloses the menu.ArrowRightopens a submenu,ArrowLeftcloses it.Home/Endjump to first/last item. Type characters to search. - ARIA attributes: Uses
role="menu",role="menuitem",role="menuitemcheckbox",role="menuitemradio",role="separator", androle="group"for semantic meaning.aria-haspopup,aria-expanded, andaria-checkedcommunicate state. - Focus behavior: Focus is trapped within the open menu. First item is auto-focused on open. Focus returns to trigger on close.
Screen reader behavior
Screen readers will announce the component as a "menu" when opened, reading each item with its role, state (checked, disabled), and available keyboard shortcuts. Submenus are announced with expanded/collapsed state to indicate hierarchy. Checkbox items announce their checked state, and radio items communicate selection within the group.
Component Folder Structure
ContextMenu/
├── index.ts
├── types.ts
├── hooks.ts
├── ContextMenu.tsx
├── ContextMenuTrigger.tsx
├── ContextMenuContent.tsx
├── ContextMenuItem.tsx
├── ContextMenuCheckBoxItem.tsx
├── ContextMenuRadioGroup.tsx
├── ContextMenuSub.tsx
├── ContextMenuSeparator.tsx
├── ContextMenuLabel.tsx
└── README.mdProps
ContextMenu
| Prop | Type | Description |
|---|---|---|
onOpenChange | (open: boolean) => void | Callback fired when the menu open state changes. |
children | React.ReactNode | The content of the context menu. |
ContextMenu.Trigger
| Prop | Type | Description |
|---|---|---|
disabled | boolean | When true, prevents the context menu from opening on right-click. |
children | React.ReactNode | The element that serves as the right-click target area. |
ContextMenu.Content
| Prop | Type | Default | Description |
|---|---|---|---|
align | "start" | "center" | "end" | "start" | Alignment of the menu relative to the cursor. |
sideOffset | number | 0 | Distance offset from the cursor position. |
children | React.ReactNode | — | The menu items and groups to render. |
ContextMenu.Item
| Prop | Type | Description |
|---|---|---|
icon | React.ReactNode | An optional icon displayed before the item text. |
shortcut | string | A keyboard shortcut hint displayed at the end of the item. |
destructive | boolean | When true, styles the item with a danger appearance. |
disabled | boolean | When true, prevents user interaction with the item. |
onSelect | () => void | Event handler called when the user selects the item. |
children | React.ReactNode | The label content of the menu item. |
ContextMenu.CheckboxItem
| Prop | Type | Description |
|---|---|---|
checked | boolean | The controlled checked state of the item. |
onCheckedChange | (checked: boolean) => void | Event handler called when the checked state changes. |
icon | React.ReactNode | An optional icon displayed before the item text. |
shortcut | string | A keyboard shortcut hint displayed at the end of the item. |
disabled | boolean | When true, prevents user interaction with the item. |
children | React.ReactNode | The label content of the checkbox item. |
ContextMenu.RadioGroup
| Prop | Type | Description |
|---|---|---|
value | string | The value of the currently selected radio item. |
onValueChange | (value: string) => void | Event handler called when the value changes. |
children | React.ReactNode | The radio items to render inside the group. |
ContextMenu.RadioItem
| Prop | Type | Description |
|---|---|---|
value | string | The unique value that identifies this radio item. |
icon | React.ReactNode | An optional icon displayed before the item text. |
shortcut | string | A keyboard shortcut hint displayed at the end of the item. |
disabled | boolean | When true, prevents user interaction with the item. |
children | React.ReactNode | The label content of the radio item. |
ContextMenu.Sub
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | Must contain a SubTrigger and SubContent. |
ContextMenu.SubTrigger
| Prop | Type | Description |
|---|---|---|
icon | React.ReactNode | An optional icon displayed before the trigger text. |
disabled | boolean | When true, prevents the submenu from opening. |
children | React.ReactNode | The label content of the submenu trigger. |
ContextMenu.SubContent
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The menu items to render inside the submenu. |
ContextMenu.Separator
No meaningful props.
ContextMenu.Label
No meaningful props.