Skip to main content

Context Menu

A context menu component that appears on right-click. Built on Base UI ContextMenu primitive with the same item API as Menu.

Compound Components

ContextMenu.Root

The root container that manages context menu state.
open
boolean
Controlled open state. When provided, the menu becomes controlled.
defaultOpen
boolean
default:"false"
Uncontrolled default open state.
onOpenChange
(open: boolean) => void
Callback fired when the open state changes.

ContextMenu.Trigger

The element that triggers the context menu on right-click.
className
string
Additional CSS classes to apply.
asChild
boolean
default:"false"
Merge props onto the child element instead of rendering a div.

ContextMenu.Portal

Portals the menu content to the end of the document body.
keepMounted
boolean
default:"false"
Whether to keep the menu mounted in the DOM when closed.
container
HTMLElement | null
The container element to portal into. Defaults to document.body.

ContextMenu.Positioner

Positions the menu at the cursor position.
sideOffset
number
default:"4"
The distance in pixels from the cursor.
collisionPadding
number | { top?: number; right?: number; bottom?: number; left?: number }
default:"8"
The padding in pixels from the viewport edges.

ContextMenu.Popup

The context menu popup container with list styles.
className
string
Additional CSS classes to apply. Default: Surface overlay background with shadow.
Layout:
  • Min-width: 220px
  • Max-width: 400px
  • Max-height: 320px
  • Vertical scrolling when content overflows

ContextMenu.Arrow

Optional arrow pointing to the trigger position.
className
string
Additional CSS classes to apply. Default: "fill-surface-overlay"
A clickable context menu item. Same component as Menu.
onSelect
(event: Event) => void
Callback fired when the item is selected.
disabled
boolean
default:"false"
Whether the item is disabled.
closeOnSelect
boolean
default:"true"
Whether to close the menu when this item is selected.
className
string
Additional CSS classes to apply.
Leading content for a menu item (icon, avatar, etc.).
className
string
Additional CSS classes to apply.
Trailing content for a menu item (shortcut, badge, etc.).
className
string
Additional CSS classes to apply.
Visual separator between menu sections.
className
string
Additional CSS classes to apply.
Groups related menu items.
className
string
Additional CSS classes to apply.
Label for a menu group.
className
string
Additional CSS classes to apply. Default: Small subtle text with padding.
Empty state message when menu has no items.
className
string
Additional CSS classes to apply.

ContextMenu.RadioGroup

Groups radio items with single selection.
value
string
The currently selected value.
onValueChange
(value: string) => void
Callback fired when the selection changes.

ContextMenu.RadioItem

A radio menu item with indicator.
value
string
The value of this radio item.
disabled
boolean
default:"false"
Whether the item is disabled.
className
string
Additional CSS classes to apply.
Indicator: Shows checked circle icon (RiCheckboxCircleFill) when selected.

ContextMenu.CheckboxItem

A checkbox menu item with indicator.
checked
boolean | 'indeterminate'
The checked state.
onCheckedChange
(checked: boolean | 'indeterminate') => void
Callback fired when the checked state changes.
disabled
boolean
default:"false"
Whether the item is disabled.
className
string
Additional CSS classes to apply.
Indicator: Shows checked circle icon (RiCheckboxCircleFill) when checked.

ContextMenu.SubmenuRoot

Root container for a submenu.
open
boolean
Controlled open state.
defaultOpen
boolean
default:"false"
Uncontrolled default open state.
onOpenChange
(open: boolean) => void
Callback fired when the submenu open state changes.

ContextMenu.SubmenuTrigger

Trigger for opening a submenu.
className
string
Additional CSS classes to apply.

Usage

import { 
  ContextMenu, 
  MenuItem, 
  MenuPrefix, 
  MenuSuffix, 
  MenuSeparator 
} from '@soft-ui/react/context-menu'
import { 
  RiFileCopyLine, 
  RiScissorsCutLine, 
  RiClipboardLine, 
  RiDeleteBinLine 
} from '@soft-ui/icons'

function Example() {
  return (
    <ContextMenu.Root>
      <ContextMenu.Trigger asChild>
        <div className="p-8 border border-border-subtle rounded-lg">
          Right-click me
        </div>
      </ContextMenu.Trigger>
      <ContextMenu.Portal>
        <ContextMenu.Positioner>
          <ContextMenu.Popup>
            <MenuItem>
              <MenuPrefix><RiFileCopyLine /></MenuPrefix>
              Copy
              <MenuSuffix>⌘C</MenuSuffix>
            </MenuItem>
            <MenuItem>
              <MenuPrefix><RiScissorsCutLine /></MenuPrefix>
              Cut
              <MenuSuffix>⌘X</MenuSuffix>
            </MenuItem>
            <MenuItem>
              <MenuPrefix><RiClipboardLine /></MenuPrefix>
              Paste
              <MenuSuffix>⌘V</MenuSuffix>
            </MenuItem>
            <MenuSeparator />
            <MenuItem>
              <MenuPrefix><RiDeleteBinLine /></MenuPrefix>
              Delete
            </MenuItem>
          </ContextMenu.Popup>
        </ContextMenu.Positioner>
      </ContextMenu.Portal>
    </ContextMenu.Root>
  )
}

With Checkbox Items

<ContextMenu.Popup>
  <ContextMenu.CheckboxItem 
    checked={showGrid} 
    onCheckedChange={setShowGrid}
  >
    Show Grid
  </ContextMenu.CheckboxItem>
  <ContextMenu.CheckboxItem 
    checked={showRulers} 
    onCheckedChange={setShowRulers}
  >
    Show Rulers
  </ContextMenu.CheckboxItem>
</ContextMenu.Popup>
<ContextMenu.Popup>
  <MenuItem>New File</MenuItem>
  <ContextMenu.SubmenuRoot>
    <ContextMenu.SubmenuTrigger>
      More Actions
      <MenuSuffix><RiArrowRightSLine /></MenuSuffix>
    </ContextMenu.SubmenuTrigger>
    <ContextMenu.Portal>
      <ContextMenu.Positioner>
        <ContextMenu.Popup>
          <MenuItem>Rename</MenuItem>
          <MenuItem>Duplicate</MenuItem>
          <MenuItem>Archive</MenuItem>
        </ContextMenu.Popup>
      </ContextMenu.Positioner>
    </ContextMenu.Portal>
  </ContextMenu.SubmenuRoot>
</ContextMenu.Popup>

Types

export type ContextMenuRootProps = {
  open?: boolean
  defaultOpen?: boolean
  onOpenChange?: (open: boolean) => void
  children?: React.ReactNode
}

export type ContextMenuPopupProps = {
  className?: string
  children?: React.ReactNode
}

Accessibility

  • Opens on right-click or Shift+F10
  • Arrow keys navigate between items
  • Enter or Space selects an item
  • Escape closes the menu
  • Focus is trapped within the menu when open

Build docs developers (and LLMs) love