Content
- Row labels start with a verb: Make intro, Copy profile link, Stop sharing.
The one ⋮ overflow menu for a row or card's actions.
import { … } from "@brdgapp/ui/components/action-menu"ActionMenu is Bridge's one ⋮ menu: the actions for a row, a card or a profile. The trigger, the floating panel and the rows all come from here, so every menu opens, moves and closes the same way. The usual mistake is building a second kebab from scratch (a raw dropdown, a hand-made portal, a different dots icon).
renderTrigger).description) when each choice needs a word of explanation.One of each
Bridge has one button, one label, one menu, one tooltip, one confirm dialog and one table. Before building a control, look for it here. Never hand-make a second version (a <button> with pill classes, a <span> chip, a new kebab), even if it looks the same today: copies drift.
Trigger. A vertical-dots IconButton (or your own, via renderTrigger).
Panel. 248px wide, raised surface, 12px corners, the menu shadow. Opens below, aligned to the trigger's right edge.
Row. Icon + label, 13px. Optional muted second line. danger rows are red.
Separator. A thin line between groups.
Open it with the keyboard: Tab to ⋮, then Enter and the arrow keys.
Leah Okonkwo
Partner, Saltmarsh Partners
Shows its own result, then the menu can be closed.
| Rest | Hover | Focus | Disabled | |
|---|---|---|---|---|
| Trigger | ||||
| Row | ||||
| Danger row |
| State | What happens |
|---|---|
| Highlighted | The row under the pointer or keyboard gets a light fill. |
| Disabled | 60% opacity; skipped by the keyboard. |
| Danger | --danger-text, with a red tint when highlighted. |
closeOnClick={false} (for a row that shows its own result, like "Copied!").href makes a link row; external opens it in a new tab. For your router's link, pass render={<Link href=… />}.Do
Name the trigger after what it acts on: "Actions for Leah Okonkwo".Don't
Leave every kebab on a list called "More options".Do
Put danger rows last, after a separator.Don't
Mix "Stop sharing" between harmless actions.| Keys | Action |
|---|---|
| EnterSpace↓ | Open the menu from the trigger. |
| ↑↓ | Move between rows. |
| Enter | Choose a row. |
| Esc | Close and return to the trigger. |
ActionMenu
The menu and its trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
ariaLabel | string | "More options" | Names the default trigger. |
size | "sm" | "md" | "md" | Trigger size. |
width | number | 248 | Panel width in px. |
icon | ReactNode | — | Trigger icon (default: vertical dots). |
onOpenChange | (open) => void | — | Know when it opens, e.g. to load data. |
renderTrigger | (props, { open }) => ReactElement | — | A custom trigger. Spread props onto it so keyboard opening works too. |
stopPropagation | boolean | true | Keep the trigger's click off a clickable row. |
children | ReactNode | (close) => ReactNode | — | The rows. |
ActionMenuItem
One row.
| Prop | Type | Default | Description |
|---|---|---|---|
icon | ReactNode | — | A bare Lucide icon. |
description | ReactNode | — | A muted second line. |
onClick | () => void | — | What it does. |
href | string | — | Makes it a link. |
external | boolean | false | Open the link in a new tab. |
render | ReactElement | — | Your router's link element. |
danger | boolean | false | Red. |
disabled | boolean | false | Can't be chosen. |
closeOnClick | boolean | true | Close the menu after choosing. |
ActionMenuSeparator
A line between groups.
| Prop | Type | Default | Description |
|---|
useActionMenu
Returns { close }, to close the menu from a custom control inside it.
| Prop | Type | Default | Description |
|---|
What it's built from and where it's used, read from the code. When you change it, check these too.
Where the code still differs from the system. Follow the system, not the gap.
Link automatically. The package doesn't depend on Next.js, so pass render={<Link href=… />}; href alone makes a plain link (a full page load).ACTION_MENU_ITEM_CLASS. Those aren't menu items, so arrow keys skip them. Move them to ActionMenuItem with closeOnClick={false}.components.md → ActionMenu / ActionMenuItem; src/components/ui/action-menu.tsx.