An action menu from a button: groups, headings, separators, icons, links and danger items, in a frosted popover.
Menu lists actions (not choices; that is Select). Items can be links (rendered as Next Links) or callbacks, carry an icon and a description, and be marked danger or disabled. It shares Select's popover family.
Installation
npx shadcn@latest add KezLahd/rime/menuAlso installs: base, icon.
Usage
import { Menu } from "@/components/ui";
<Menu label="Actions" items={[{ id: "edit", label: "Edit", onSelect: edit }, { id: "sep", separator: true }, { id: "void", label: "Void invoice", tone: "danger", onSelect: confirm }]} />Examples
Open
Default
API
Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.
Menu
| Prop | Type | Default | Description |
|---|---|---|---|
| labelRequired | ReactNode | Trigger content. A chevron is appended unless iconOnly or hideChevron. | |
| aria-label | string | Accessible name when the trigger content is not descriptive (an avatar, an icon). | |
| itemsRequired | ReadonlyArray<MenuEntry> | ||
| header | ReactNode | Tinted block at the top of the menu: name and ID number, say. | |
| align | "start" | "end" | "end" | |
| iconOnly | boolean | Icon-only trigger (a "more" ellipsis): a square ghost button, no chevron. Give it an aria-label. | |
| hideChevron | boolean | Drops the chevron from a custom trigger that signals the menu another way. | |
| disabled | boolean | ||
| triggerClassName | string | ||
| className | string | ||
| inline | boolean | false | Render the menu open, in place, under its trigger: no portal, no focus move, no outside-click listener. For docs and thumbnails. |
Theme tokens
Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.
| Token | Default | Live value |
|---|---|---|
| --chip-radius | var(--r-sm) | … |
| --popover-item-active-bg | linear-gradient(to right, rgba(var(--rgb-brand), 0.14), rgba(var(--rgb-brand-deep), 0.07)) | … |
| --popover-item-press-bg | linear-gradient(to right, rgba(var(--rgb-brand), 0.2), rgba(var(--rgb-brand-deep), 0.1)) | … |
| --popover-item-radius | var(--r-xs) | … |
| --popover-pad | calc(6px * var(--density)) | … |
| --popover-radius | var(--r-lg) | … |
| --recess-fill-disabled | rgba(var(--rgb-white), 0.3) | … |
System tokens it reads
| Token | Default | Live value |
|---|---|---|
| --blur-recess | tokens.css | … |
| --border-w | tokens.css | … |
| --brand-gradient-wash | tokens.css | … |
| --danger-ink | tokens.css | … |
| --density | tokens.css | … |
| --dur | tokens.css | … |
| --dur-fast | tokens.css | … |
| --ease | tokens.css | … |
| --ease-out | tokens.css | … |
| --focus-halo | tokens.css | … |
| --focus-ring | tokens.css | … |
| --font-body | tokens.css | … |
| --ink-body | tokens.css | … |
| --ink-brand | tokens.css | … |
| --ink-disabled | tokens.css | … |
| --ink-heading | tokens.css | … |
| --ink-muted | tokens.css | … |
| --ink-secondary | tokens.css | … |
| --line-soft | tokens.css | … |
| --popover-blur | tokens.css | … |
| --popover-border | tokens.css | … |
| --popover-shadow | tokens.css | … |
| --popover-surface | tokens.css | … |
| --r-lg | tokens.css | … |
| --r-sm | tokens.css | … |
| --r-xs | tokens.css | … |
| --recess-fill | tokens.css | … |
| --recess-fill-hover | tokens.css | … |
| --rgb-brand | tokens.css | … |
| --rgb-brand-deep | tokens.css | … |
| --rgb-contact | tokens.css | … |
| --rgb-danger | tokens.css | … |
| --rgb-white | tokens.css | … |
| --shadow-recess | tokens.css | … |
| --text-caption | tokens.css | … |
| --text-micro | tokens.css | … |
| --text-small | tokens.css | … |
| --tracking-label | tokens.css | … |
| --wash-active | tokens.css | … |
| --wash-subtle | tokens.css | … |
| --z-popover | tokens.css | … |
Accessibility
- role="menu" with roving focus: arrows, Home, End, typeahead; Esc and Tab close and return focus to the trigger.
Do and don't
Do
- Put destructive items last, after a separator.
Don't
- Don't hide the only way to do something important in a menu.
For AI agents
This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.
Open menu.md