Context Menu
Right-click menu with items, checkboxes, radio groups, and submenus.
import * as ContextMenu from '@gentleduck/primitives/context-menu'import * as ContextMenu from '@gentleduck/primitives/context-menu'Anatomy
<ContextMenu.Root>
<ContextMenu.Trigger />
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Label />
<ContextMenu.Item />
<ContextMenu.Group>
<ContextMenu.Item />
</ContextMenu.Group>
<ContextMenu.CheckboxItem>
<ContextMenu.ItemIndicator />
</ContextMenu.CheckboxItem>
<ContextMenu.RadioGroup>
<ContextMenu.RadioItem>
<ContextMenu.ItemIndicator />
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger />
<ContextMenu.SubContent />
</ContextMenu.Sub>
<ContextMenu.Arrow />
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root><ContextMenu.Root>
<ContextMenu.Trigger />
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Label />
<ContextMenu.Item />
<ContextMenu.Group>
<ContextMenu.Item />
</ContextMenu.Group>
<ContextMenu.CheckboxItem>
<ContextMenu.ItemIndicator />
</ContextMenu.CheckboxItem>
<ContextMenu.RadioGroup>
<ContextMenu.RadioItem>
<ContextMenu.ItemIndicator />
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger />
<ContextMenu.SubContent />
</ContextMenu.Sub>
<ContextMenu.Arrow />
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>Example
import * as ContextMenu from '@gentleduck/primitives/context-menu'
function FileExplorer() {
return (
<ContextMenu.Root>
<ContextMenu.Trigger className="w-64 h-64 border-2 border-dashed rounded flex items-center justify-center">
Right-click here
</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="bg-white shadow-lg rounded-md p-1 min-w-[180px] border">
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
New File
</ContextMenu.Item>
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
New Folder
</ContextMenu.Item>
<ContextMenu.Separator className="h-px bg-gray-200 my-1" />
<ContextMenu.Sub>
<ContextMenu.SubTrigger className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer flex justify-between">
Sort by <span>></span>
</ContextMenu.SubTrigger>
<ContextMenu.SubContent className="bg-white shadow-lg rounded-md p-1 min-w-[140px] border">
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
Name
</ContextMenu.Item>
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
Date
</ContextMenu.Item>
</ContextMenu.SubContent>
</ContextMenu.Sub>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
)
}import * as ContextMenu from '@gentleduck/primitives/context-menu'
function FileExplorer() {
return (
<ContextMenu.Root>
<ContextMenu.Trigger className="w-64 h-64 border-2 border-dashed rounded flex items-center justify-center">
Right-click here
</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="bg-white shadow-lg rounded-md p-1 min-w-[180px] border">
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
New File
</ContextMenu.Item>
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
New Folder
</ContextMenu.Item>
<ContextMenu.Separator className="h-px bg-gray-200 my-1" />
<ContextMenu.Sub>
<ContextMenu.SubTrigger className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer flex justify-between">
Sort by <span>></span>
</ContextMenu.SubTrigger>
<ContextMenu.SubContent className="bg-white shadow-lg rounded-md p-1 min-w-[140px] border">
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
Name
</ContextMenu.Item>
<ContextMenu.Item className="px-3 py-1.5 rounded hover:bg-gray-100 cursor-pointer">
Date
</ContextMenu.Item>
</ContextMenu.SubContent>
</ContextMenu.Sub>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
)
}Key components
ContextMenu.Root
State manager. Opens on right-click on the trigger area.
| Prop | Type | Default | Description |
|---|---|---|---|
onOpenChange | (open: boolean) => void | -- | Called when open state changes |
dir | 'ltr' | 'rtl' | -- | Reading direction for keyboard navigation |
modal | boolean | true | Enable modal behavior |
ContextMenu.Trigger
The area that responds to right-click. Renders a <span> by default.
ContextMenu.Content
The menu content. Positioned at the cursor location.
ContextMenu.Item
A menu item. Fires onSelect when activated.
| Prop | Type | Description |
|---|---|---|
disabled | boolean | Disable the item |
onSelect | (event) => void | Called when item is selected |
ContextMenu.CheckboxItem
A toggleable menu item with checked state.
| Prop | Type | Description |
|---|---|---|
checked | boolean | 'indeterminate' | Checked state |
onCheckedChange | (checked: boolean) => void | Called on toggle |
ContextMenu.RadioGroup / ContextMenu.RadioItem
Mutually exclusive menu items.
ContextMenu.Sub / ContextMenu.SubTrigger / ContextMenu.SubContent
Nested submenus.
ContextMenu.Separator
Visual separator between groups.
ContextMenu.Label
Non-interactive label for a group.
Keyboard interactions
| Key | Action |
|---|---|
| ArrowDown | Highlight next item |
| ArrowUp | Highlight previous item |
| ArrowRight | Open submenu (on SubTrigger) |
| ArrowLeft | Close submenu |
| Enter / Space | Activate highlighted item |
| Escape | Close menu |