Phoundry UI

Context Menu

Right-click context menu overlay with nested submenus, optional horizontal icon groups, shortcuts, boolean toggles, and danger actions.

import { useContextMenuAPI, contextMenu } from 'phoundry-ui';

Programmatic Open

Show code
const api = useContextMenuAPI();

const items: MenuItem[] = [
  { type: 'action', label: 'Copy', icon: 'carbon:copy', id: 'copy', action: () => {} },
  { type: 'separator' },
  { type: 'action', label: 'Delete', danger: true, id: 'del', action: () => {} },
];

api.open(() => items, e.clientX, e.clientY, { ariaLabel: 'Edit actions' });

Right-Click Area (Attachment)

Right-click anywhere in this area
Show code
<div {@attach contextMenu({ api, items: menuItems })}>
  Right-click here
</div>

OpenMenuOptions (4th argument to api.open)

PropTypeDefaultDescription
ariaLabel stringAccessible name for the menu panel. Defaults to `"Context menu"`.
anchor 'start' | 'end'Horizontal alignment relative to the open point.
side PopoverSideWhich edge of the trigger the menu opens from. Defaults to `'bottom'`.
onClose () => voidCalled when the menu closes (Escape, backdrop, or after an action).
trigger unknownOptional trigger reference for callers that track menu origin.

ActionMenuItem

PropTypeDefaultDescription
type required'action'Menu item that triggers a callback.
id requiredstringStable key for shortcuts / analytics.
label requiredstringDisplay text.
icon stringIconify icon string.
shortcut stringDisplay-only shortcut hint.
pluginId stringOptional plugin scope for shortcut manager lookups (`pluginId.id`).
danger booleanfalseRed danger styling.
disabled booleanfalseNon-interactive row.
selected booleanDecorates the row as checked/active where supported.
preventClose booleanfalseKeep the overlay open after invoking the action.
action required() => void | Promise<void>Handler run when the row is activated.

BooleanMenuItem

PropTypeDefaultDescription
type required'boolean'Toggle row with checkbox on the right.
label requiredstringDisplay text.
icon stringIconify icon string.
pluginId stringPlugin ID (same role as on action items).
preventClose booleanfalseKeep the menu open after toggling.
value requiredbooleanChecked state.
onchange required(nextValue: boolean) => void | Promise<void>Called with the new value after the user toggles the row.

SubmenuMenuItem

PropTypeDefaultDescription
type required'submenu'Nested submenu container.
label requiredstringSubmenu trigger label.
items requiredMenuItem[]Child menu items.

GroupMenuItem

PropTypeDefaultDescription
type required'group'Horizontal row of icon-only controls.
id requiredstringStable key (see MenuItemBase).
items requiredGroupMenuChildItem[]Toolbar row: **`action`** and **`boolean`** as icon-only `Button`s (labels via tooltip / `aria-label`); **`separator`** as a vertical rule.
disabled booleanfalseDisables all controls in the group.

SeparatorMenuItem

PropTypeDefaultDescription
type required'separator'Horizontal rule between groups.

LabelMenuItem

PropTypeDefaultDescription
type required'label'Non-interactive heading row.
label requiredstringMuted caption text.

CustomMenuItem

PropTypeDefaultDescription
type required'custom'Fully custom row body via snippet.
id requiredstringStable key.
render requiredSnippetSnippet rendered inside the menu row.
disabled booleanfalseSkip pointer interaction.

Usage tips

  • provideContextMenu() must be called in the root layout, and ContextMenuOverlay must be rendered there — or call setupOverlays() once to initialize all overlay managers together.
  • The menu auto-positions to stay within the viewport.
  • Arrow keys, Home, and End move the highlighted row; Enter and Space activate it. Escape closes the menu. The active row uses the same background as hover; focus returns to the element that opened the menu.
  • api.open accepts either a static array or () => MenuItem[] so menus can read live state (as with the attachment demo). Pass ariaLabel in the fourth argument when the default "Context menu" label is too generic.
  • For click-based dropdowns from a button, use ButtonDropdown instead.