API reference

The API consists of: (1) the object returned by createContextMenu(config) and its methods, (2) the config options you pass to createContextMenu, and (3) the menu item types you use inside menu.


Instance methods

What you get from createContextMenu(config):

open

Shows the menu. Single unified method for all open cases.

  • Signature: open(xOrEventOrElement?, yOrOptions?): Promise<MenuItem | undefined>
  • No args: Uses getAnchor from config, or (0, 0).
  • (x, y): Opens at coordinates.
  • (event): Opens at the event client position.
  • (element, options?): Opens next to the element (placement, offset).
  • Returns: Promise that resolves with the selected item when the menu closes, or undefined if closed without selection.
const selected = await menu.open(200, 100);
if (selected) console.log("Selected:", selected.label);
 
element.addEventListener("contextmenu", (e) => {
  e.preventDefault();
  menu.open(e);
});
 
// Next to an element (dropdown-style)
await menu.open(button, { placement: "bottom-start", offset: { x: 0, y: 4 } });

close

Closes the menu and runs the leave animation. Returns a Promise that resolves when the close animation finishes.

  • Signature: close(): Promise<void>
await menu.close();

getState

Returns the current state: { isOpen, anchor, menu, rootElement }. menu is a copy of the current items. Use this instead of separate isOpen(), getAnchor(), getMenu(), or getRootElement().

  • Signature: getState(): ContextMenuState
const { isOpen, anchor, menu, rootElement } = menu.getState();

bind

Attaches the menu to an element so it opens on right-click (desktop) or long-press (touch). Call bind() or bind(null) to unbind.

  • Signature: bind(element?: HTMLElement | null, options?: { longPressMs?: number }): void
  • longPressMs: Delay in ms before the menu opens on touch (default 500).
menu.bind(document.getElementById("area"), { longPressMs: 400 });
menu.bind(); // or menu.bind(null) — unbind

setMenu

Sets the menu. Pass an array to replace, or a function (current) => newItems to update from current state.

  • Signature: setMenu(menuOrUpdater: MenuItem[] | ((current: MenuItem[]) => MenuItem[])): void
menu.setMenu([
  { label: "Option A", onClick: () => {} },
  { label: "Option B", onClick: () => {} },
]);
 
// Updater (e.g. persist checkbox state)
menu.setMenu((current) =>
  current.map((item) =>
    item.type === "checkbox" && item.label === "Dark mode"
      ? { ...item, checked: !item.checked }
      : item
  )
);

setOptions

Updates theme, position, animation, or lockScrollOutside at runtime. Only the keys you pass are applied. Same shapes as in config.

  • Signature: setOptions(options: ContextMenuInstanceOptions): void
menu.setOptions({ theme: { class: "my-dark", tokens: { bg: "#1a1a1a", fg: "#eee" } } });
menu.setOptions({ position: { padding: 12, zIndexBase: 10000 } });
menu.setOptions({ animation: { enter: 150, leave: 100 } });
menu.setOptions({ lockScrollOutside: false });
menu.setOptions({ theme: undefined }); // clear theme

destroy

Removes the menu DOM and all event listeners. Call this when the component or page is torn down.

  • Signature: destroy(): void
menu.destroy();

Config options

What you pass to createContextMenu:


Each entry in the menu array (and in submenu children) is one of the following types. Omitted type defaults to an action item.

Action (default)

Clickable item. No need to set type unless you use another type.

{ label: "Copy", shortcut: "Ctrl+C", onClick: () => copy() }
{ label: "Delete", variant: "danger", onClick: ({ close }) => { remove(); close(); } }

Opens a URL. Use type: "link".

{ type: "link", label: "Documentation", href: "https://example.com/docs", target: "_blank" }

Opens a nested list. Use type: "submenu".

{ type: "submenu", label: "More", children: [
  { label: "Rename", onClick: () => rename() },
  { label: "Delete", onClick: () => remove() },
]}

Separator

Horizontal divider.

{ type: "separator" }

Checkbox

Toggle item. Use type: "checkbox".

{ type: "checkbox", label: "Show grid", checked: showGrid, onChange: (v) => setShowGrid(v) }

Radio

Single selection within a group. Use type: "radio".

{ type: "radio", name: "size", label: "Small", value: "s", checked: size === "s", onSelect: () => setSize("s") }
{ type: "radio", name: "size", label: "Large", value: "l", checked: size === "l", onSelect: () => setSize("l") }

Label

Non-clickable header or section title. Use type: "label".

{ type: "label", label: "Section title" }