Overlays
Context menu
A right-click menu — `DropdownMenu`'s behaviour, anchored to a point instead of a button.
Import
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuTrigger } from '@the_viveksingh/vivek-ui'Right-click, or Shift+F10
contextmenu is a pointer event, so a menu that opens only on it does not exist for keyboard users. The surface is focusable and opens on Shift+F10 and the ContextMenu key at its own centre; closing returns focus to wherever it was. Inside, it is DropdownMenu: roving arrows, typeahead, aria-disabled items that stay announced.
Nothing selected yet. Escape returns focus to where it was.
<ContextMenu>
<ContextMenu.Trigger>Right-click here</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Label>Report</ContextMenu.Label>
<ContextMenu.Item onSelect={duplicate} shortcut="⌘D">Duplicate</ContextMenu.Item>
<ContextMenu.Item onSelect={rename} shortcut="F2">Rename</ContextMenu.Item>
<ContextMenu.Item disabled shortcut="⌘P">Print</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item onSelect={trash}>Move to trash</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu>
// Any element can be the surface, and an item can be a real link:
<ContextMenu.Trigger asChild><tr>...</tr></ContextMenu.Trigger>
<ContextMenu.Item asChild><Link href="/reports/42">Open</Link></ContextMenu.Item>Props
Generated from the package's own type declarations, so this table cannot drift from the code.
| Prop | Type | Default | Description |
|---|---|---|---|
children required | ReactNode | — | — |
onOpenChange | (open: boolean) => void | — | — |
container | PortalContainer | — | Where the menu portals. Defaults to `document.body`. |
loop | boolean | — | Arrow keys wrap at the ends. Default `true`. |
typeahead | boolean | — | Typing a letter jumps to the next matching item. Default `true`. |
Exports
ContextMenuContextMenuContentContextMenuItemContextMenuLabelContextMenuSeparatorContextMenuTriggerRendering
ContextMenu declares 'use client' because it needs state, effects or event handlers. Importing it into a Server Component creates a client boundary at this component — everything above it stays on the server.