Context Menu

@sushindustries/ui

One menu, reachable by right-click, by long press, and by a button that is always there.

4 min read
View as Markdown
Viewport width
Desktop100%whatever the page has
tanstacktanstack add https://adamjurek.com/r/tanstack/context-menu.jsonshadcnpnpm dlx shadcn@latest add https://adamjurek.com/r/shadcn/context-menu.json

Actions are the consumer's

const menu = useContextMenu();

<div {...menu.triggerProps}>
	<button {...menu.buttonProps}>Actions</button>
</div>

<ContextMenu state={menu} actions={actions} />
tsx

MenuAction is an id, a label, an optional glyph and hint, and an onSelect that may be async. This component knows how to summon a menu and where to put it; it does not know what "save as Markdown" means and should not.

Where this is used

WhereActions
FolderShelf tiles and rowssupplied by actionsFor
The home page desktopapps/web/src/modules/chrome/shelf-actions.ts

Those actions are worth reading as an example of degrading rather than hiding: the share sheet is not on most desktop browsers and the clipboard is not available over plain HTTP, and neither is a reason to remove a menu item. Each falls back to the thing the reader would have done by hand.

Used byFolder ShelfFolder ShelfA desktop of folders that open into draggable windows, several at once, remembered between visits.@sushindustries/ui · layout