[ @sdxc/ui ]
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/ui remiximport "@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, muted, and set in tabular digits so the hints of a column of rows line up.
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">.