Mosmox UI
Current version
GitHubnpmjs.com
Overlays

Context Menu

Cursor-positioned actions for a target, powered by the shared Menu component.

ContextMenu combines a target area with the existing Menu component. It renders the menu in a portal, opens on a right-click, positions it near the pointer, keeps it inside the viewport, and supports keyboard invocation with Shift + F10 or the Context Menu key.

Basic usage

<ContextMenu
  aria-label="Project actions"
  entries={[
    { key: 'open', label: 'Open' },
    { key: 'rename', label: 'Rename', shortcut: 'F2' },
    { type: 'divider' },
    { key: 'delete', label: 'Delete', danger: true },
  ]}
  onSelect={(key) => handleProjectAction(project, key)}
>
  <ProjectRow project={project} />
</ContextMenu>

The target can be a card, table row, list item, canvas region, button, or any other React content. entries uses the same MenuEntry[] type as Menu, including icons, descriptions, images, shortcuts, labels, dividers, disabled items, danger actions, and nested submenus.

Keyboard and dismissal

Focus the target and press Shift + F10 or the keyboard Context Menu key to open the menu without a pointer. Escape closes it and returns focus to the target. By default, a mousedown outside the menu, scrolling, or menu selection closes it; control these behaviors with closeOnOutsideClick, closeOnEscape, and closeOnSelect.

<ContextMenu
  entries={actions}
  closeOnSelect={false}
  menuProps={{ selectable: true, selectedKeys: selectedKeys }}
>
  <button type="button">Focus and use Shift + F10</button>
</ContextMenu>

Controlled state and positioning

Use open and onOpenChange when an application owns the menu lifecycle. The callback receives the next state and the pointer position. position can provide a controlled anchor point in viewport coordinates; otherwise the component uses the most recent pointer or keyboard target position.

<ContextMenu
  open={open}
  position={{ x: 240, y: 180 }}
  onOpenChange={(nextOpen, point) => {
    setOpen(nextOpen);
    if (point) setLastPoint(point);
  }}
  entries={actions}
>
  <CanvasRegion />
</ContextMenu>

offset controls the distance between the pointer and the menu. The component clamps both coordinates so that the menu remains visible inside the viewport. Use menuWidth or menuProps to customize the shared Menu size, variant, keyboard behavior, selection, max height, and footer. Set preventDefault={false} when the browser's native context menu should remain available, or disabled to disable the context-menu behavior for a target.

API Reference

PropertyTypeDefaultDescription
childrenReactNode—Target that receives context-menu and keyboard events.
entriesMenuEntry[]—Items passed to the shared Menu.
aria-labelstring'Context menu'Accessible menu name.
classNamestring—Class name applied to the target wrapper.
idstringGeneratedID applied to the portalled menu popover.
onSelect(key, item) => void—Called when a menu item is selected.
openboolean—Controlled open state.
defaultOpenbooleanfalseInitial uncontrolled open state.
onOpenChange(open, position?) => void—Called when the menu opens or closes; opening provides the trigger position.
position{ x: number; y: number }Last trigger pointControlled viewport coordinates used as the menu anchor.
offsetnumber4Gap between trigger point and menu in pixels.
menuWidthnumber | string280Menu width.
menuPropsMenuProps without entries, onSelect, aria-label, width—Additional shared Menu options.
closeOnEscapebooleantrueCloses on Escape.
closeOnOutsideClickbooleantrueCloses when clicking outside.
closeOnSelectbooleantrueCloses after an item is selected.
preventDefaultbooleantruePrevents the browser context menu.
disabledbooleanfalseDisables context-menu behavior.

Use Menu directly when the menu is already visible in the page, and ButtonMenu when a visible button should own the trigger. Use ContextMenu when actions are tied to a target and should appear at the pointer location.