Skip to main content

ContextMenu

ContextMenu provides a fully accessible, keyboard-navigable right-click menu for contextual actions. It supports separators, icons, danger items, disabled states, and renders via a portal.


Usage​

Basic usage​

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

<ContextMenu
trigger={<div>Right-click me</div>}
items={[
{ label: 'Edit', onSelect: () => {} },
{ label: 'Rename', onSelect: () => {} },
]}
/>;

With icons, separators, and danger items​

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

<ContextMenu
trigger={<Button>Options</Button>}
items={[
{ label: 'Open', icon: 'πŸ“‚' },
{ label: 'Copy', icon: 'πŸ“„' },
{ type: 'separator' },
{
label: 'Delete',
icon: 'πŸ—‘',
danger: true,
onSelect: () => alert('Delete'),
},
]}
/>;

Variants​

ContextMenu does not expose visual variants directly. Styling is controlled via CSS and the optional className prop.

Guidelines:

  • Use danger: true for destructive actions.
  • Keep labels short and action-oriented.
  • Group related actions using separators.

Sizes​

ContextMenu does not support size props.

Sizing is controlled via CSS (min-width, padding, font size). You may override styles using a custom class.


States​

Each menu item supports multiple states:

{
label: "Delete",
danger: true,
disabled: false,
onSelect: () => {}
}
  • disabled

    • Item is skipped during keyboard navigation
    • Clicks are ignored
    • Visual opacity is reduced
  • danger

    • Item is styled as destructive
    • Intended for irreversible actions

Native Props / Composition​

Trigger​

The trigger prop accepts any ReactNode and listens for the contextmenu (right-click) event.

<ContextMenu
trigger={<div className="custom-trigger">Right click</div>}
items={items}
/>

Custom styling​

<ContextMenu
className="my-contextmenu"
trigger={<div>Trigger</div>}
items={items}
/>

Props​

ContextMenu​

PropTypeDefaultDescription
triggerReactNodeβ€”Element that opens the context menu on right-click
itemsMenuItem[]β€”Menu configuration array
classNamestring""Additional class name for menu container
PropTypeDefaultDescription
labelstringβ€”Text label for the item
iconReactNodeβ€”Optional leading icon
onSelect() => voidβ€”Called when item is selected
dangerbooleanfalseMarks item as destructive
disabledbooleanfalseDisables interaction and navigation
type"item" | "separator""item"Renders a separator instead of item

Behavior Notes​

  • Opens on right-click (contextmenu) only

  • Automatically positions at cursor location

  • Closes when:

    • Clicking outside
    • Pressing Escape
    • Selecting an item
  • Uses roving active index for keyboard navigation

  • Disabled and separator items are skipped during navigation


Accessibility​

  • Renders with role="menu" and role="menuitem"

  • Keyboard support:

    • ArrowUp / ArrowDown β€” navigate items
    • Home / End β€” jump to first/last enabled item
    • Enter / Space β€” activate item
    • Escape β€” close menu
  • Disabled items use aria-disabled

  • Focus is managed internally for predictable navigation


Layout​

  • Rendered in a portal (outside normal DOM flow)
  • Uses position: fixed for accurate cursor placement
  • Menu width adapts to content (min-width: 180px by default)
<ContextMenu
trigger={<div style={{ width: '100%' }}>Full-width trigger</div>}
items={items}
/>

Best Practices​

Do​

  • Use for contextual, secondary actions
  • Group related actions with separators
  • Mark destructive actions with danger
  • Keep menus short and focused

Don’t​

  • Use as a primary navigation menu
  • Overload with too many options
  • Place critical actions without confirmation
  • Rely on icons without text labels