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
getAnchorfrom 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
undefinedif 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) — unbindsetMenu
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 themedestroy
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:
Menu item types
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(); } }Link
Opens a URL. Use type: "link".
{ type: "link", label: "Documentation", href: "https://example.com/docs", target: "_blank" }Submenu
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" }