ContextMenu
A menu surface that opens at a right-click's pointer position, composing Menu's popover styling and role="menu" wiring directly so its rows read and behave exactly like a standard menu's.
Right-click a row, or focus it and press the Context Menu key.
2.4 MB · edited by Ana Souza · yesterday
View code
<div mix={[vstack({ gap: 2, align: "stretch" }), is("100%"), maxIs("28rem")]}>
<p mix={[text("sm"), fg("neutral")]}>Right-click a row, or focus it and press the Context Menu key.</p>
<ContextMenu.Trigger
tabIndex={0}
aria-label="q3-board-review.pdf, press the Context Menu key for actions"
mix={[
rounded("lg"),
border({ color: "neutral", width: 1 }),
p(1),
contextMenu("preview-row-menu"),
]}
>
<Item>
<Item.Media>
<FileTextIcon size={18} aria-hidden="true" />
</Item.Media>
<Item.Content>
<Item.Title>q3-board-review.pdf</Item.Title>
<Item.Description>2.4 MB · edited by Ana Souza · yesterday</Item.Description>
</Item.Content>
</Item>
</ContextMenu.Trigger>
<ContextMenu id="preview-row-menu" aria-label="File actions" mix={[menuKeys()]}>
<ContextMenu.Group aria-labelledby="preview-row-menu-file">
<ContextMenu.Label id="preview-row-menu-file">File</ContextMenu.Label>
<ContextMenu.Item mix={[hstack({ gap: 2, align: "center" })]}>
<PencilIcon size={16} aria-hidden="true" />
Rename
<ContextMenu.Shortcut>F2</ContextMenu.Shortcut>
</ContextMenu.Item>
<ContextMenu.Item mix={[hstack({ gap: 2, align: "center" })]}>
<CopyIcon size={16} aria-hidden="true" />
Duplicate
<ContextMenu.Shortcut>⌘D</ContextMenu.Shortcut>
</ContextMenu.Item>
<ContextMenu.Item href="#download" mix={[hstack({ gap: 2, align: "center" })]}>
<DownloadIcon size={16} aria-hidden="true" />
Download
</ContextMenu.Item>
</ContextMenu.Group>
<ContextMenu.Group aria-labelledby="preview-row-menu-share">
<ContextMenu.Label id="preview-row-menu-share">Share</ContextMenu.Label>
<ContextMenu.SubTrigger commandfor="preview-row-menu-share-surface" command="toggle-popover">
Send a copy
<ChevronRightIcon data-slot="icon" size={16} aria-hidden="true" />
</ContextMenu.SubTrigger>
<ContextMenu.CheckboxItem aria-selected="true">Anyone with the link</ContextMenu.CheckboxItem>
</ContextMenu.Group>
<ContextMenu.Separator />
<ContextMenu.Item danger mix={[hstack({ gap: 2, align: "center" })]}>
<Trash2Icon size={16} aria-hidden="true" />
<span mix={[weight("medium")]}>Move to trash</span>
<ContextMenu.Shortcut>⌫</ContextMenu.Shortcut>
</ContextMenu.Item>
</ContextMenu>
<ContextMenu.SubContent
id="preview-row-menu-share-surface"
aria-label="Send a copy"
mix={[menuKeys()]}
>
<ContextMenu.Item>Email</ContextMenu.Item>
<ContextMenu.Item>Slack</ContextMenu.Item>
<ContextMenu.Item>Copy link</ContextMenu.Item>
</ContextMenu.SubContent>
</div>Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/uiimport "@sdxc/ui/theme.css";Usage
import { ContextMenu } from "@sdxc/ui";Renders Menu unchanged; positioning against the pointer is handled
entirely by the contextMenu() mixin a consuming island applies to
ContextMenu.Trigger, while every nested row stays a real, tab-reachable <a> or <button>.
Composition
The parts the component publishes, each a static property of the host.
ContextMenuContextMenu.TriggerRenders ContextMenu.TriggerProps.children inside a plain<div>, the area a pointer gesture opens the paired ContextMenu against.ContextMenu.GroupRenders ContextMenu.GroupProps.children as one labeled run of rows: Section restyled with a divider above every group but the first.ContextMenu.LabelRenders ContextMenu.LabelProps.children as a ContextMenu.Group's small, muted heading, sized and spaced to sit directly above the group's first row for a dense row of actions.ContextMenu.SubTriggerRenders a row that opens a nested ContextMenu.SubContent surface: Menu.Item restyled with inline-end padding for a trailing chevron icon; pointcommandforat the nested surface'sidwithcommand="toggle-popover".ContextMenu.SubContentRenders a nested surface opened by a ContextMenu.SubTrigger row: ContextMenu itself, defaultingplacementto DEFAULT_SUB_PLACEMENT since a nested row conventionally opens beside itself.ContextMenu.ShortcutRenders ContextMenu.ShortcutProps.children as a row's trailing keyboard-shortcut hint: pushed to the row's inline end and muted, reading as supplementary detail alongside the row's primary label.
Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
Also accepts everything in Menu.Props.
ContextMenu.Trigger
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The content the pointer gesture opens ContextMenu against. |
Also accepts everything in TagProps<"div">.
ContextMenu.Group
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The group's rows, typically a ContextMenu.Label followed by a run of ContextMenu.Items. |
Also accepts everything in Section.Props.
ContextMenu.Label
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The group's visible label text. |
Also accepts everything in TagProps<"header">.
ContextMenu.SubTrigger
ContextMenu.SubContent
Also accepts everything in Props.
ContextMenu.Shortcut
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The shortcut hint text, typically a key combination like "⌘⇧D". |
Also accepts everything in TagProps<"span">.