Context Menu

@sushindustries/ui

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

6 min read
View as MarkdownEdit on GitHub
Viewport width
Phone22remthe floor, the narrowest this promises to work at
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.

UsesIconIconThe glyph set, generated from a Markdown table where every drawing carries its reason. One component, typed names, no icon font.@sushindustries/ui · content
Used byFolder ShelfFolder ShelfA desktop of folders that open into draggable windows, several at once, remembered between visits.@sushindustries/ui · layout