Skip to main content

ContextMenu

A right-click triggered contextual action menu that provides spatially anchored commands with keyboard navigation, collision-aware positioning, accessibility semantics, and portal-based rendering.

Supports icons, separators, disabled items, danger actions, focus management, keyboard navigation, viewport collision detection, and trigger composition via asChild.


Usage

Basic Context Menu

import { ContextMenu } from '@nofinite/nui';

<ContextMenu
items={[
{ label: 'Rename', onSelect: () => rename() },
{ label: 'Duplicate', onSelect: () => duplicate() },
{ type: 'separator' },
{ label: 'Delete', danger: true, onSelect: () => remove() },
]}
>
<div>Right click me</div>
</ContextMenu>;

With Icons

<ContextMenu
items={[
{ label: 'Copy', icon: <CopyIcon />, onSelect: copy },
{ label: 'Paste', icon: <PasteIcon />, onSelect: paste },
]}
>
<FileCard />
</ContextMenu>

Disabled Items

<ContextMenu
items={[
{ label: 'Open', onSelect: openFile },
{ label: 'Rename', disabled: true },
{ label: 'Delete', danger: true, onSelect: deleteFile },
]}
>
<FileRow />
</ContextMenu>

Using asChild Trigger

<ContextMenu asChild items={items}>
<Button variant="ghost">Right click</Button>
</ContextMenu>

Props

PropTypeDefaultDescription
childrenReactNodeTrigger element
itemsContextMenuItem[]Menu items definition
classNamestring""Custom panel styling
asChildbooleanfalseAvoid wrapper and attach handler directly

ContextMenuItem Structure

FieldTypeDescription
labelstringItem text
iconReactNodeOptional leading icon
onSelect() => voidAction handler
dangerbooleanHighlights destructive action
disabledbooleanDisables interaction
type'item' | 'separator'Item or divider

Variants

<ContextMenu items={items} />                 // Default
<ContextMenu items={itemsWithIcons} /> // Icon items
<ContextMenu items={itemsWithSeparator} /> // Divider groups
<ContextMenu items={dangerItems} /> // Danger actions

Available variants

  • default — Standard contextual actions
  • icon — Items with visual affordances
  • grouped — Separator-based grouping
  • danger — Destructive emphasis items

Guidelines

  • Use default for simple action lists
  • Use icon when recognition speed matters
  • Use grouped to separate semantic clusters
  • Use danger only for destructive operations

States

StateDescription
closedMenu hidden
openMenu visible
activeKeyboard highlighted item
disabledNon-interactive item
dangerDestructive action styling

Keyboard Interaction

KeyBehavior
ArrowDownMove to next enabled item
ArrowUpMove to previous enabled item
HomeJump to first enabled item
EndJump to last enabled item
Enter / SpaceExecute active item
EscapeClose menu

Accessibility

  • Implements ARIA menu pattern
  • Focus automatically moved to menu on open
  • Active item tracked via keyboard navigation
  • aria-disabled for disabled items
  • Screen reader friendly separators
  • Click-outside and Escape dismissal
  • Scroll/resize auto-dismiss for spatial correctness

Design Tokens

:root {
--nui-radius-lg: 12px;
--nui-radius-sm: 4px;
--nui-space-1: 4px;
--nui-space-2: 8px;

--nui-bg-surface: #ffffff;
--nui-bg-subtle: #f3f4f6;
--nui-border-default: #e5e7eb;
--nui-fg-default: #111827;
--nui-fg-muted: #6b7280;
--nui-color-danger: #ef4444;
}

Best Practices

Do

  • Use for contextual object-level actions
  • Keep menus short and relevant
  • Group related commands with separators
  • Use danger styling for destructive actions
  • Provide icons for high-frequency workflows

Don’t

  • Place global navigation commands inside context menu
  • Include too many actions causing cognitive overload
  • Mix unrelated destructive and safe actions
  • Disable keyboard navigation
  • Rely solely on hover for discoverability