sdxc

Type to search, or start from one of these:

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.

q3-board-review.pdf

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
import "@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.

  • ContextMenu
  • ContextMenu.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; point commandfor at the nested surface's id with command="toggle-popover".
  • ContextMenu.SubContentRenders a nested surface opened by a ContextMenu.SubTrigger row: ContextMenu itself, defaulting placement to 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

PropTypeDescription
childrenRemixNodeThe content the pointer gesture opens ContextMenu against.

Also accepts everything in TagProps<"div">.

ContextMenu.Group

PropTypeDescription
childrenRemixNodeThe group's rows, typically a ContextMenu.Label followed by a run of ContextMenu.Items.

Also accepts everything in Section.Props.

ContextMenu.Label

PropTypeDescription
childrenRemixNodeThe group's visible label text.

Also accepts everything in TagProps<"header">.

ContextMenu.SubTrigger

ContextMenu.SubContent

Also accepts everything in Props.

ContextMenu.Shortcut

PropTypeDescription
childrenRemixNodeThe shortcut hint text, typically a key combination like "⌘⇧D".

Also accepts everything in TagProps<"span">.