Overview
Right-click anywhere in this area
Context Menu opens on right-click (or long-press on mobile) over a target area, providing context-sensitive actions for that element. It shares the same item primitives as DropdownMenu.
Installation
npm install @araf-ds/core
Usage
import {
ContextMenu ,
ContextMenuTrigger ,
ContextMenuContent ,
ContextMenuItem ,
ContextMenuSeparator ,
ContextMenuShortcut ,
} from "@araf-ds/core"
export default function Example () {
return (
< ContextMenu >
< ContextMenuTrigger className = "border-2 border-dashed rounded-lg p-8 text-sm text-muted-foreground" >
Right-click here
</ ContextMenuTrigger >
< ContextMenuContent className = "w-48" >
< ContextMenuItem >
< EditIcon size = { 13 } /> Edit
< ContextMenuShortcut > ⌘E </ ContextMenuShortcut >
</ ContextMenuItem >
< ContextMenuItem >
< LinkIcon size = { 13 } /> Copy link
< ContextMenuShortcut > ⌘C </ ContextMenuShortcut >
</ ContextMenuItem >
< ContextMenuSeparator />
< ContextMenuItem variant = "destructive" >
< TrashIcon size = { 13 } /> Delete
< ContextMenuShortcut > ⌫ </ ContextMenuShortcut >
</ ContextMenuItem >
</ ContextMenuContent >
</ ContextMenu >
)
}
Variants
With Checkbox and Radio Items
< ContextMenuContent >
< ContextMenuCheckboxItem
checked = { showBookmarks }
onCheckedChange = { setShowBookmarks }
>
Show bookmarks < ContextMenuShortcut > ⌘⇧B </ ContextMenuShortcut >
</ ContextMenuCheckboxItem >
< ContextMenuSeparator />
< ContextMenuRadioGroup value = { person } onValueChange = { setPerson } >
< ContextMenuLabel > People </ ContextMenuLabel >
< ContextMenuRadioItem value = "pedro" > Pedro Duarte </ ContextMenuRadioItem >
< ContextMenuRadioItem value = "colm" > Colm Tuite </ ContextMenuRadioItem >
</ ContextMenuRadioGroup >
</ ContextMenuContent >
< ContextMenu >
< ContextMenuTrigger asChild >
< TableRow className = "cursor-context-menu" >
< TableCell > { row . name } </ TableCell >
< TableCell > { row . status } </ TableCell >
</ TableRow >
</ ContextMenuTrigger >
< ContextMenuContent >
< ContextMenuItem onSelect = { () => editRow ( row . id ) } >
< EditIcon size = { 13 } /> Edit
</ ContextMenuItem >
< ContextMenuItem onSelect = { () => duplicateRow ( row . id ) } >
< CopyIcon size = { 13 } /> Duplicate
</ ContextMenuItem >
< ContextMenuSeparator />
< ContextMenuItem variant = "destructive" onSelect = { () => deleteRow ( row . id ) } >
< TrashIcon size = { 13 } /> Delete
</ ContextMenuItem >
</ ContextMenuContent >
</ ContextMenu >
API Reference
Offset from the cursor position on the alignment axis.
Additional class names for the menu panel.
Visual style. "destructive" renders item text in red.
Callback fired when item is selected. Menu closes automatically.
Accessibility
Context Menu opens at the cursor position with role="menu"
ContextMenuTrigger area does not show a visual indicator — consider adding a subtle hint for discoverability
Keyboard: Shift+F10 or the Menu key opens context menu at the focused element
All the same keyboard navigation as DropdownMenu applies (Arrow keys, Enter, Escape)
Do’s & Don’ts
Do
Use Context Menu for actions directly tied to the right-clicked element
Include keyboard shortcuts to mirror native OS conventions
Keep items to 5–8 max — only actions relevant to that specific element
Use on data-dense areas: table rows, file lists, canvas elements
Don't
Don’t rely solely on right-click — always provide primary action buttons too
Don’t use Context Menu as a main navigation mechanism
Don’t add items that aren’t contextually relevant to the trigger area
Don’t show a Context Menu on mobile without a fallback (long-press isn’t obvious)