A list of actions attached to a button: the row "⋯" menu, "New ▾", the user menu, column visibility. Icons, shortcuts, descriptions, checkbox and radio items, submenus and destructive items — plus ActionMenu, a one-line menu built from data.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, ActionMenu } from "@vamos-ui/react";
<DropdownMenu>
<DropdownMenuTrigger asChild><Button>New</Button></DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem icon={<Newspaper />} shortcut="mod+alt+n">Post</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
// from data
<ActionMenu items={[{ id: "edit", label: "Edit", onSelect: edit }, { type: "separator" }, …]} />Keyboard: Enter, Space or ↓ opens; ↑ ↓ Home End move; typing jumps to an item; → opens a submenu (← in RTL); Escape closes and returns focus to the trigger.
Content portals into the nearest ThemeScope. The root menu is layer depth 1 (blurred in glass mode); submenus are deeper and opaque.
Shortcut keycaps are hints only. Register the real shortcut with useHotkeys.
Examples
Row actions
The "⋯" menu on a CRM deal row: shortcuts, a link item (asChild), a disabled item and a danger item.
Northwind Logistics — fleet renewal
Negotiation$48,200Harbor & Pine — POS rollout (14 sites)
Proposal$126,500Checkbox and radio items
Column visibility and sorting for an HR people table. preventDefault in onSelect keeps the menu open.
Async item
event.preventDefault() keeps the menu open while a spinner runs; the other items are disabled meanwhile.
API
DropdownMenu
| Prop | Type | Default |
|---|---|---|
open / defaultOpen / onOpenChangeControlled or uncontrolled. | boolean / boolean / (open) => void | — |
modalBlock outside interaction while open. | boolean | true |
dirReading direction (inherits from the Direction provider). | "ltr" | "rtl" | — |
DropdownMenuContent
| Prop | Type | Default |
|---|---|---|
sizeMin width 180 / 220 px; items follow the size. | "sm" | "md" | "md" |
alignAlignment against the trigger. | "start" | "center" | "end" | "start" |
sidePreferred side; flips on collision. | "top" | "right" | "bottom" | "left" | "bottom" |
sideOffsetGap to the trigger in px. | number | 6 |
loopArrow keys wrap around. | boolean | false |
DropdownMenuItem
| Prop | Type | Default |
|---|---|---|
iconLeading icon. | ReactNode | — |
descriptionSecond line under the label. | ReactNode | — |
shortcutShortcut hint as Kbd ("mod+d"). Display only — bind it with useHotkeys. | string | string[] | — |
badgeTrailing count or badge. | ReactNode | — |
tonedanger for destructive actions. | "default" | "danger" | "default" |
insetAlign with checkbox/radio labels. | boolean | false |
onSelectClick, Enter or Space. preventDefault keeps the menu open. | (event: Event) => void | — |
disabledSkipped by keyboard navigation. | boolean | false |
textValueTypeahead text when the label isn't plain text. | string | — |
asChildRender your link as the item (put icon and text inside it). | boolean | false |
DropdownMenuCheckboxItem · DropdownMenuRadioGroup · DropdownMenuRadioItem
| Prop | Type | Default |
|---|---|---|
checked / onCheckedChangeCheckbox item state (menuitemcheckbox). | boolean | "indeterminate" / (checked) => void | — |
value / onValueChangeRadio group state. | string / (value) => void | — |
valueRadio item value (menuitemradio). | string | — |
shortcut · descriptionSame as on items. | string · ReactNode | — |
DropdownMenuSub · DropdownMenuSubTrigger · DropdownMenuSubContent
| Prop | Type | Default |
|---|---|---|
SubTrigger iconLeading icon; a chevron is added (mirrored in RTL). | ReactNode | — |
SubContent sizeWidth of the submenu. | "sm" | "md" | parent size |
Sub open / onOpenChangeControl the submenu. | boolean / (open) => void | — |
DropdownMenuLabel · DropdownMenuSeparator · DropdownMenuGroup · DropdownMenuShortcut
| Prop | Type | Default |
|---|---|---|
insetLabel aligned with checkbox/radio labels. | boolean | false |
DropdownMenuShortcutPlain-text trailing hint when keycaps are too much. | span props | — |
ActionMenu
| Prop | Type | Default |
|---|---|---|
itemsitem · checkbox · radio · submenu · group · label · separator. Shared with Context Menu and Command. | MenuEntry[] | — |
triggerCustom trigger. Default: a "⋯" IconButton. | ReactElement | — |
triggerLabelAccessible name of the default trigger (actionMenu.trigger). | string | "More actions" |
triggerSizeSize of the default trigger. | "xs" | "sm" | "md" | "sm" |
size / align / sidePassed to the content. | DropdownMenuContent props | align "end" |
open / defaultOpen / onOpenChange / modalPassed to the root. | Root props | — |
labelsBuilt-in string overrides. | { trigger?: string } | — |
MenuEntry (item)
| Prop | Type | Default |
|---|---|---|
id · labelStable key and label. | string · ReactNode | — |
icon · description · shortcut · badge · toneItem look. | as on DropdownMenuItem | — |
onSelect / hrefAction, or a link rendered with the app's Link. | () => void / string | — |
permissionHidden unless can(permission) is true. Hiding is not security. | string | — |
disabled · textValueDisabled state and typeahead text. | boolean · string | — |