Dropdown

A menu of actions and nested choices opened from a trigger.

Default

Open on click from any trigger. DropdownMenuContent has no default width, so give it one, such as w-56. Items close the menu when chosen.

Width

Set the width on DropdownMenuContent to fit the longest label. Use w-(--anchor-width) to match the trigger, as a select does.

Groups and separators

Flat lists need no dividers. Separate distinct groups with DropdownMenuSeparator, or wrap them in DropdownMenuGroup with separated. Destructive items use variant="danger" and go last.

Leading and trailing

Use leading for an icon and trailing for fixed content such as a DropdownMenuShortcut, a count or a status. Icons render at 18px.

Descriptions

Pass description for a supporting line under the label. With selected, the chosen row shows a trailing checkmark instead of a fill.

Avatars

Put a 16px Avatar in leading to identify people or agents in the row.

Disabled

Pass disabled to show an action that is unavailable right now. It dims to 50% and cannot be chosen.

Single select

Wrap DropdownMenuRadioItems in a DropdownMenuRadioGroup. The selected row shows a trailing checkmark without a row fill, and choosing a row closes the menu.

Multi select

DropdownMenuCheckboxItems show a leading circular checkbox and keep the menu open while people pick several values.

Multi select with icons

Pass indicatorPosition="trailing" when each option has a leading icon, so the checkboxes line up in one column.

Select all

Pin an “All” row above a separator and derive its checked state from the rest.

Long labels

Labels wrap by default, so nothing is hidden. To keep every row on one line, wrap the label in a span with truncate and put the full text in title.

Long lists

The menu stops at 500px or the space left in the viewport, whichever is smaller, and the list scrolls with a fade at the cut edge.

Floating submenu

DropdownMenuSub opens a side panel from its DropdownMenuSubTrigger on hover or with the right arrow key. Floating is the default variant.

Inline submenu

variant="inline" with a unique name drills into the same surface. The panel slides in with a back row labelled by title, and the menu height follows the visible pane.

Account menu

Use size="lg" with interactive={false} for an identity header that shows the name and email but runs no action. A large avatar goes in trailing, and actions follow a separator.

Workspace switcher

Show the active workspace as a non-interactive lg header, then actions, then the other workspaces in a ScrollArea with scrollFade and a max height.

Best practices

  • Use for contextual actions on one resource (“Edit agent”, “Duplicate agent”) or a compact set of related choices such as a digest frequency.
  • Use Split Button for two frequent related actions, and Select or Combobox for form values that submit with a form.
  • DropdownMenuContent has no default width; always pass one, such as className="w-56", and keep it constant for the menu's lifetime.
  • Items close the menu on click. Checkbox items stay open for multi-select; radio items close on choice.
  • Single select uses DropdownMenuRadioGroup with a trailing check and no row fill; multi select uses DropdownMenuCheckboxItem. Pass indicatorPosition="trailing" when rows have leading icons.
  • Submenus float by default. Use variant="inline" with a unique name to drill into the same surface when the panel needs its own search, aside or footer.
  • Submenus have no search by default; pass search={<DropdownMenuSearch />} to DropdownMenuSubPanel when a panel has more than about eight options.
  • Filter search results yourself and show a DropdownMenuLabel such as “No voices match” when nothing is left.
  • Pin persistent actions with DropdownMenuFooter; use variant="caption" for a line of help text.
  • Use size="lg" for rows with a 32–40px avatar or workspace mark, and interactive={false} for identity headers that run no action.
  • Long option lists scroll inside the menu (capped at 500px); for grouped lists inside a menu use ScrollArea with scrollFade and a max height on viewportClassName.
  • Use sentence-case verb + noun actions: “Delete project”, not “Delete” or “Delete Project”.
  • Separate distinct groups with DropdownMenuSeparator or DropdownMenuGroup separated; flat lists need no dividers.
  • Put destructive actions last with variant="danger", behind a separator or in the footer.
  • Put the current account or workspace in a non-interactive lg header, then actions, then the switcher list.
  • Give every DropdownMenuSearch an aria-label as well as a placeholder.
  • Icon-only triggers need an aria-label that names the menu, such as “Agent actions”.
  • Arrow keys, Enter, Escape and Tab still reach the menu from the search field; do not stop those keys in onKeyDown.