ComponentsOverlays & feedback

Dropdown Menu

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.

Radix Dropdown Menu components/dropdown-menu.tsx, lib/menu.tsx, lib/variants.tstheme · material · accent · density · font

Installation

$ pnpm add @vamos-ui/react

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,200

Harbor & Pine — POS rollout (14 sites)

Proposal$126,500

Checkbox and radio items

Column visibility and sorting for an HR people table. preventDefault in onSelect keeps the menu open.

User menu

Account card trigger, grouped items, a theme radio submenu and sign out.

ActionMenu from data

One MenuEntry[] per row. Entries whose permission fails the VamosProvider can() check are hidden, and dangling separators are dropped.

INV-2041Northwind LogisticsOverdue$12,480.00
INV-2042Harbor & PineSent$3,915.50
INV-2043Lumen Dental GroupPaid$860.00

Async item

event.preventDefault() keeps the menu open while a spinner runs; the other items are disabled meanwhile.

API

DropdownMenu

PropTypeDefault
open / defaultOpen / onOpenChange
Controlled or uncontrolled.
boolean / boolean / (open) => void—
modal
Block outside interaction while open.
booleantrue
dir
Reading direction (inherits from the Direction provider).
"ltr" | "rtl"—

DropdownMenuContent

PropTypeDefault
size
Min width 180 / 220 px; items follow the size.
"sm" | "md""md"
align
Alignment against the trigger.
"start" | "center" | "end""start"
side
Preferred side; flips on collision.
"top" | "right" | "bottom" | "left""bottom"
sideOffset
Gap to the trigger in px.
number6
loop
Arrow keys wrap around.
booleanfalse

DropdownMenuItem

PropTypeDefault
icon
Leading icon.
ReactNode—
description
Second line under the label.
ReactNode—
shortcut
Shortcut hint as Kbd ("mod+d"). Display only — bind it with useHotkeys.
string | string[]—
badge
Trailing count or badge.
ReactNode—
tone
danger for destructive actions.
"default" | "danger""default"
inset
Align with checkbox/radio labels.
booleanfalse
onSelect
Click, Enter or Space. preventDefault keeps the menu open.
(event: Event) => void—
disabled
Skipped by keyboard navigation.
booleanfalse
textValue
Typeahead text when the label isn't plain text.
string—
asChild
Render your link as the item (put icon and text inside it).
booleanfalse

DropdownMenuCheckboxItem · DropdownMenuRadioGroup · DropdownMenuRadioItem

PropTypeDefault
checked / onCheckedChange
Checkbox item state (menuitemcheckbox).
boolean | "indeterminate" / (checked) => void—
value / onValueChange
Radio group state.
string / (value) => void—
value
Radio item value (menuitemradio).
string—
shortcut · description
Same as on items.
string · ReactNode—

DropdownMenuSub · DropdownMenuSubTrigger · DropdownMenuSubContent

PropTypeDefault
SubTrigger icon
Leading icon; a chevron is added (mirrored in RTL).
ReactNode—
SubContent size
Width of the submenu.
"sm" | "md"parent size
Sub open / onOpenChange
Control the submenu.
boolean / (open) => void—

DropdownMenuLabel · DropdownMenuSeparator · DropdownMenuGroup · DropdownMenuShortcut

PropTypeDefault
inset
Label aligned with checkbox/radio labels.
booleanfalse
DropdownMenuShortcut
Plain-text trailing hint when keycaps are too much.
span props—

ActionMenu

PropTypeDefault
items
item · checkbox · radio · submenu · group · label · separator. Shared with Context Menu and Command.
MenuEntry[]—
trigger
Custom trigger. Default: a "⋯" IconButton.
ReactElement—
triggerLabel
Accessible name of the default trigger (actionMenu.trigger).
string"More actions"
triggerSize
Size of the default trigger.
"xs" | "sm" | "md""sm"
size / align / side
Passed to the content.
DropdownMenuContent propsalign "end"
open / defaultOpen / onOpenChange / modal
Passed to the root.
Root props—
labels
Built-in string overrides.
{ trigger?: string }—

MenuEntry (item)

PropTypeDefault
id · label
Stable key and label.
string · ReactNode—
icon · description · shortcut · badge · tone
Item look.
as on DropdownMenuItem—
onSelect / href
Action, or a link rendered with the app's Link.
() => void / string—
permission
Hidden unless can(permission) is true. Hiding is not security.
string—
disabled · textValue
Disabled state and typeahead text.
boolean · string—