Context menu
A ContextMenu opens a menu of actions where the user right-clicks. It wraps a target element and shows a PopoverNext at the pointer.
Usage#
import { ContextMenu, Menu, MenuItem } from "@clawscale/react";ContextMenu renders a div around its children and passes extra props to it. Change the element with tagName.
Examples#
Basic#
Pass a Menu as content. Right-click the card.
import { Card, Classes, ContextMenu, EntityTitle, Menu, MenuDivider, MenuItem } from "@clawscale/react";
export default function ContextMenuBasic() {
return (
<ContextMenu
content={
<Menu>
<MenuItem icon="eye-open" text="Preview rows" />
<MenuItem icon="duplicate" text="Copy table path" />
<MenuItem icon="edit" text="Rename" />
<MenuDivider />
<MenuItem icon="trash" intent="danger" text="Delete dataset" />
</Menu>
}
>
<Card style={{ width: 300 }}>
<EntityTitle icon="database" title="orders_daily" subtitle="1,284,112 rows, updated 4 min ago" />
<p className={Classes.TEXT_MUTED} style={{ margin: "12px 0 0" }}>
Right-click for actions.
</p>
</Card>
</ContextMenu>
);
}Table rows#
tagName="tr" makes each row its own target. Right-click a row.
| Run | Pipeline | Status |
|---|---|---|
| 4812 | ingest-orders | Running |
| 4811 | sessionize-events | Failed |
| 4810 | nightly-rollup | Succeeded |
import { ContextMenu, HTMLTable, Menu, MenuDivider, MenuItem, Tag } from "@clawscale/react";
const runs = [
{ id: 4812, pipeline: "ingest-orders", status: "Running", intent: "primary" },
{ id: 4811, pipeline: "sessionize-events", status: "Failed", intent: "danger" },
{ id: 4810, pipeline: "nightly-rollup", status: "Succeeded", intent: "success" },
] as const;
export default function ContextMenuTable() {
return (
<HTMLTable compact interactive style={{ width: "100%" }}>
<thead>
<tr>
<th>Run</th>
<th>Pipeline</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{runs.map((run) => (
<ContextMenu
key={run.id}
tagName="tr"
content={
<Menu>
<MenuItem icon="document-open" text={`Open run ${run.id}`} />
<MenuItem icon="console" text="View logs" />
<MenuItem icon="refresh" text="Rerun" />
<MenuDivider />
<MenuItem disabled={run.status !== "Running"} icon="stop" intent="danger" text="Cancel run" />
</Menu>
}
>
<td>{run.id}</td>
<td>{run.pipeline}</td>
<td>
<Tag intent={run.intent} minimal>
{run.status}
</Tag>
</td>
</ContextMenu>
))}
</tbody>
</HTMLTable>
);
}Imperative API#
showContextMenu opens a menu at any position, for example from a canvas or chart event handler. hideContextMenu closes it. The menu renders in a separate React root, so it cannot read your React context.
import { Card, Menu, MenuItem, showContextMenu, Tag } from "@clawscale/react";
import type { MouseEvent } from "react";
const tables = ["events_raw", "sessions", "orders_daily", "revenue_by_region"];
export default function ContextMenuImperative() {
const openMenu = (event: MouseEvent<HTMLElement>, table: string) => {
event.preventDefault();
showContextMenu({
content: (
<Menu>
<MenuItem icon="eye-open" text={`Preview ${table}`} />
<MenuItem icon="data-lineage" text="Show upstream tables" />
<MenuItem icon="duplicate" text="Copy table name" />
</Menu>
),
targetOffset: { left: event.clientX, top: event.clientY },
});
};
return (
<Card style={{ display: "flex", flexWrap: "wrap", gap: 8, maxWidth: 420 }}>
{tables.map((table) => (
<Tag key={table} icon="th" interactive minimal onContextMenu={(event) => openMenu(event, table)}>
{table}
</Tag>
))}
</Card>
);
}Without a wrapper#
To skip the wrapper element, pass a function as children. Spread its class name, handler and ref onto your element and render its popover.
<ContextMenu content={menu}>
{(target) => (
<div className={target.className} onContextMenu={target.onContextMenu} ref={target.ref}>
{target.popover}
orders_daily
</div>
)}
</ContextMenu>content can also be a function. It receives isOpen, targetOffset and mouseEvent, for menus that depend on where the user clicked.
Theme#
Menus follow the dark color scheme through the bp6-dark class that ClawscaleProvider puts on <html>.
Props interface#
interface ContextMenuProps extends Omit<React.HTMLAttributes<HTMLElement>, "children" | "className" | "content" | "onContextMenu">, React.RefAttributes<any>, Props@clawscale/react| Props | Description |
|---|---|
childrenrequired | React.ReactNode | ((props: ContextMenuChildrenProps) => React.ReactElement)The context menu target. This may optionally be a render function so you can use component state to render the target. |
className | stringA space-delimited list of class names to pass along to a child element. Inherited from Props |
contentrequired | React.JSX.Element | ((props: ContextMenuContentProps) => React.JSX.Element | undefined) | undefinedMenu content. This will usually be a Blueprint <Menu> component. This optionally functions as a render prop so you can use component state to render content. |
disabled | boolean = falseWhether the context menu is disabled. |
onClose | () => voidCallback invoked when the popover overlay closes. |
onContextMenu | React.MouseEventHandler<HTMLElement>An optional context menu event handler. This can be useful if you want to do something with the mouse event unrelated to rendering the context menu itself, especially if that involves setting React state (which is an error to do in the render code path of this component). |
popoverProps | ContextMenuPopoverOptionsA limited subset of props to forward along to the popover overlay generated by this component. |
tagName | keyof React.JSX.IntrinsicElements = "div"HTML tag to use for container element. Only used if this component's children are specified as React node(s), not when it is a render function (in that case, you get to render whatever tag you wish). |
ContextMenuPopover is the lower-level popover that ContextMenu and showContextMenu render. It is controlled with isOpen and targetOffset.
interface ContextMenuPopoverProps extends ContextMenuPopoverOptions@clawscale/react| Props | Description |
|---|---|
contentrequired | React.JSX.Element |
isDarkTheme | boolean |
isOpenrequired | boolean |
onClose | () => void |
onClosed | (node: HTMLElement) => voidLifecycle method invoked just after the CSS _close_ transition ends but before the child has been removed from the DOM. Receives the DOM element of the child being closed. Inherited from OverlayLifecycleProps |
onClosing | (node: HTMLElement) => voidLifecycle method invoked just before the CSS _close_ transition begins on a child. Receives the DOM element of the child being closed. Inherited from OverlayLifecycleProps |
onOpened | (node: HTMLElement) => voidLifecycle method invoked just after the CSS _open_ transition ends. Receives the DOM element of the child being opened. Inherited from OverlayLifecycleProps |
onOpening | (node: HTMLElement) => voidLifecycle method invoked just after mounting the child in the DOM but just before the CSS _open_ transition begins. Receives the DOM element of the child being opened. Inherited from OverlayLifecycleProps |
placement | Placement = "auto"The placement (relative to the target) at which the popover should appear. Mutually exclusive with Inherited from position prop. Prefer using this over position, as it more closely aligns with Popper.js semantics.PopoverSharedProps |
popoverClassName | stringA space-delimited string of class names applied to the popover element. Inherited from PopoverSharedProps |
popoverRef | React.Ref<HTMLElement>DOM ref attached to the Inherited from Classes.POPOVER element.PopoverSharedProps |
rootBoundary | RootBoundaryA root boundary element supplied to the "flip" and "preventOverflow" modifiers. This is a shorthand for overriding Popper.js modifier options with the Inherited from modifiers prop.PopoverSharedProps |
targetOffsetrequired | Offset | undefined |
transitionDuration | number = 300Indicates how long (in milliseconds) the overlay's enter/leave transition takes. This is used by React Inherited from CSSTransition to know when a transition completes and must match the duration of the animation in CSS. Only set this prop if you override Blueprint's default transitions with new transitions of a different length.OverlayableProps |
interface ShowContextMenuOptions@clawscale/reactOptions for specifying how an imperatively created context menu should be rendered to the DOM.
| Props | Description |
|---|---|
container | HTMLElement = document.bodyA new DOM element will be created and appended to this container. |
render | ShowContextMenuDOMRendererA function render the React component onto a newly created DOM element. This should return a function which unmounts the rendered element from the DOM. |