v1.0

Dropdown Menu

Action menu that opens from a button, for account controls, row actions, and overflow commands.

Pro

Description

Dropdown is a compound menu built on React Aria's Menu. It composes a trigger, a Dropdown.Popover surface, and a Dropdown.Menu list of Dropdown.Item rows, with optional Dropdown.Section, Dropdown.Header, Dropdown.Search, Dropdown.Misc, and Dropdown.Footer slots. size is set on the root and cascades through context to every item, label, and icon.

Reach for it when a button needs to fan out into a short list of commands or one-of-many switches: account menus, row actions, overflow ("...") menus on cards, sort and filter pickers, "open in" link lists. It works equally well attached to a labeled icon button, an avatar, or a plain text trigger.

The free tier ships the two building blocks: Dropdown.Item and Dropdown.Separator. Grouped sections and headers, a pinned search bar, smart items (secondary text, trailing badges/switches), and the footer slot are Pro (add it with a Pro seat via add dropdown-menu). Do not use a dropdown as a form control: to bind a single value to a form field use Select; for right-click on a region use ContextMenu; for arbitrary non-menu content use Popover.

Installation

pnpm dlx @create-ui/cli add dropdown-menu

Anatomy

<Dropdown>
  <Button>Trigger</Button>
  <Dropdown.Popover>
    <Dropdown.Menu>
      <Dropdown.Section>
        <Dropdown.Header />
        <Dropdown.Item />
        <Dropdown.Separator />
      </Dropdown.Section>
    </Dropdown.Menu>
    <Dropdown.Footer />
  </Dropdown.Popover>
</Dropdown>

Usage

import { Dropdown } from "@/components/ui/dropdown-menu"
<Dropdown>
  <Button>Open</Button>
  <Dropdown.Popover className="w-56">
    <Dropdown.Menu aria-label="Account">
      <Dropdown.Item id="profile">Profile</Dropdown.Item>
      <Dropdown.Item id="settings">Settings</Dropdown.Item>
      <Dropdown.Separator />
      <Dropdown.Item id="logout">Log out</Dropdown.Item>
    </Dropdown.Menu>
  </Dropdown.Popover>
</Dropdown>

Examples

The free tier covers Dropdown.Item (with a leading icon and size) and Dropdown.Separator. Everything richer is a Pro preview, marked with a Pro badge; the live demo still runs, but the source needs a Pro seat.

Items

A smart item takes a leading icon, a secondary description line, and a trailing slot for a badge or control. The free item is a plain label with an optional leading icon.

Pro

Grouping

The free tier separates runs of items with Dropdown.Separator. Pro adds Dropdown.Section + Dropdown.Header for labeled groups.

Pro

Sizes

Three sizes (xs, sm, md) set on the root cascade to radius, item height, label, and icon size. xs is the default.

Give an item an href (and optional target) to render it as an anchor while keeping menu keyboard and focus behavior.

Disabled

Pass disabledKeys on the menu to disable rows; they are skipped by keyboard navigation.

Selection

Set selectionMode to single or multiple on the menu. Selected rows render a trailing check indicator; multi-select keeps the menu open.

Sorting

A single-select list that uses a leading Radio in place of the trailing check, with keyboard-shortcut hints in the footer.

Pro

Country picker

Dropdown.Popover takes header={<Dropdown.Search />} to pin a filter above the scrolling list; the menu filters by item textValue automatically. Grouped Popular / All sections hold single-select items with a leading flag and a trailing check.

Pro

Insert block

A command menu with a Pro upsell: a locked AI Block row and a footer pairing an "Unlock with Pro" badge with an upgrade button.

Pro

Dropdown.Footer pins a bar below the list with a top divider, for counts, buttons, or a version label.

Pro

User profile

A rich account menu: an avatar identity row, grouped settings with descriptions, an inline switch (shouldCloseOnSelect={false} keeps the menu open when you toggle it), and a version footer.

Pro

Assignee picker

A searchable multi-select with a leading Checkbox, member avatars, an empty state, and an apply/clear footer.

Pro

Token watchlist

Smart items with a brand icon, a price description, and a trailing holdings amount, grouped under section headers.

Pro

Accessibility

Dropdown inherits React Aria's menu keyboard model. The trigger is a single tab stop. Once the menu opens, arrow keys move focus between items, type-ahead jumps to a matching item, and Esc returns focus to the trigger.

KeyDescription
Space EnterOpens the menu; activates the focused item.
↑ ↓Moves focus between items inside the open menu.
Home EndJumps to the first / last item.
A-ZType-ahead; focuses the first item matching the input.
EscCloses the menu and returns focus to the trigger.
TabCloses the menu and moves focus to the next element.

ARIA notes:

  • React Aria wires role="menu" on the list, role="menuitem" (or menuitemcheckbox / menuitemradio under a selectionMode) on each item, and aria-haspopup / aria-expanded on the trigger. The popover manages focus while the menu is open.
  • Activating an item closes the menu by default. For a row that holds an interactive control (a switch, a stepper), pass shouldCloseOnSelect={false} so interacting with it does not dismiss the popover.
  • Rows disabled through disabledKeys receive data-disabled and are skipped by keyboard navigation. Always give an icon-only trigger an aria-label, and give a Dropdown.Menu an aria-label when it has no visible label.
  • For the full focus, collection, and typeahead behavior, see the React Aria Menu docs.

Styling

Tailwind override: pass className to merge Tailwind classes on Dropdown.Popover or any sub-part (merged via cn()):

<Dropdown.Popover className="w-56" />

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="dropdown-popover" on the surface, dropdown-menu on the list, dropdown-section on a group, dropdown-header on a group label, dropdown-misc on the pinned top bar, dropdown-search on the pinned search field, dropdown-separator on a divider, dropdown-item on a row, dropdown-item-label / dropdown-item-description / dropdown-item-container / dropdown-item-content / dropdown-item-indicator / dropdown-item-trailing on the item sub-parts, and dropdown-footer on the bottom bar.
  • data-size="xs" | "sm" | "md" mirrors the root size on most slots; data-variant="default" | "danger" on the item.
  • React Aria manages data-focused, data-selected, data-disabled, and data-pressed on each item; the wrapper styles react through group-data-[focused]/item and group-data-[selected]/item.

Target a state in CSS:

[data-slot="dropdown-item"][data-focused] {
  /* … */
}
  • Select: form-value picker bound to a Field. Use it when the chosen value is what the form submits.
  • Context Menu: same menu shape, triggered by right-click (or long-press) on a region.
  • Popover (Pro): arbitrary content with no menu semantics or roving focus.
  • Command (Pro): a searchable command palette in a modal shell.

API Reference

The free tier exports Dropdown, Dropdown.Popover, Dropdown.Menu, Dropdown.Item, and Dropdown.Separator. The remaining parts (Dropdown.Section, Dropdown.Header, Dropdown.Misc, Dropdown.Search, Dropdown.Footer, and the item sub-parts) are Pro.

The root. Provides the size context and wires the trigger to the popover. Extends React Aria's MenuTriggerProps, so isOpen, defaultOpen, and onOpenChange pass through. Its children are the trigger element followed by a Dropdown.Popover.

Props

PropTypeDefaultDescription
isOpenboolean-Controlled open state of the menu.
defaultOpenboolean-Uncontrolled initial open state.
onOpenChange(isOpen: boolean) => void-Fires when the menu opens or closes.
childrenReact.ReactNode-The trigger element and the Dropdown.Popover.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""xs"Cascades to radius, item height, label, and icon size. Falls back to a surrounding Field size.

The floating surface. Extends React Aria's PopoverProps.

Props

PropTypeDefaultDescription
headerReact.ReactNode-Pinned content above the list (usually <Dropdown.Search />). Wraps the menu in a filtering Autocomplete.
filter(textValue: string, inputValue: string) => boolean-Custom matcher for the header search (defaults to case-insensitive contains).
placementPlacement"bottom start"Preferred side/alignment relative to the trigger.
offsetnumber-Distance in pixels from the trigger.
classNamestring-Tailwind classes merged via cn() (commonly a width).
childrenReact.ReactNode-Dropdown.Menu, plus optional Dropdown.Search / Dropdown.Misc / Dropdown.Footer.

The scrolling list. Extends React Aria's MenuProps, so all collection and selection props pass through.

Props

PropTypeDefaultDescription
selectionMode"none" | "single" | "multiple""none"Turns rows into selectable items with a trailing check.
selectedKeysSelection-Controlled set of selected keys.
defaultSelectedKeysSelection-Uncontrolled initial selection.
onSelectionChange(keys: Selection) => void-Fires when the selection changes.
disabledKeysIterable<Key>-Keys of items to disable.
disallowEmptySelectionbooleanfalseKeep at least one item selected in single-select.
itemsIterable<T>-Data for dynamic rendering via a render-function child.
renderEmptyState() => React.ReactNode-Rendered when a filtered items list is empty.
aria-labelstring-Accessible name when there is no visible label.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode | (item: T) => ReactNode-Items, sections, and separators (static or a render function).

A menu row. Extends React Aria's MenuItemProps (minus children), so id, textValue, href, target, isDisabled, onAction, and shouldCloseOnSelect pass through. Providing leading, description, trailing, or indicator opts into the smart layout.

Props

PropTypeDefaultDescription
leadingReact.ReactNode-Leading media (icon / Avatar / token) inside the auto-built container.
descriptionReact.ReactNode-Secondary line under the label.
trailingReact.ReactNode-Trailing slot (Badge / Switch / kbd / amount); coexists with the selection check.
indicatorReact.ReactNode-Content of the selection indicator (defaults to a check). Pass null to suppress.
onAction() => void-Fires when the row is activated.
shouldCloseOnSelectbooleantrueSet false to keep the menu open when the row is activated.
hrefstring-Render the row as a link.
idKey-Stable key for selection and actions.
textValuestring-String used for type-ahead when children are not plain text.
isDisabledboolean-Disable this row.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-The row label, or a render function receiving { isSelected, ... }.

Variants

VariantOptionsDefaultDescription
variant"default" "danger""default"danger renders a destructive (error) row.

A thin divider between runs of items. Extends React Aria's SeparatorProps.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().

Groups related items under a shared label. Extends React Aria's MenuSectionProps.

Props

PropTypeDefaultDescription
childrenReactNode-A Dropdown.Header followed by the section's items.
classNamestring-Tailwind classes merged via cn().

The overline label at the top of a Dropdown.Section. Extends React Aria's HeaderProps.

Props

PropTypeDefaultDescription
childrenReactNode-The label text.
classNamestring-Tailwind classes merged via cn().

Pins arbitrary static content above the scrolling list. For a filter, prefer Dropdown.Search.

Props

PropTypeDefaultDescription
childrenReactNode-The pinned content.
classNamestring-Tailwind classes merged via cn().

A pinned search field. Pass it to Dropdown.Popover's header prop; the menu then filters by item textValue through a React Aria Autocomplete (no query state to wire up). Reads its size from the Dropdown root. Extends React Aria's SearchFieldProps.

Props

PropTypeDefaultDescription
placeholderstring"Search"Input placeholder.
iconReact.ReactNodesearch glyphLeading icon.
autoFocusbooleantrueFocus the field when the menu opens.
aria-labelstring"Search"Accessible name for the field.
inputClassNamestring-Tailwind classes for the inner input.
classNamestring-Tailwind classes for the field, merged via cn().

Pins a divided action bar below the list.

Props

PropTypeDefaultDescription
childrenReactNode-The footer content.
classNamestring-Tailwind classes merged via cn().

Item parts (Pro)

The slots a smart Dropdown.Item builds from its leading, description, trailing, and indicator props. Compose them by hand only for a custom row, such as a leading Checkbox beside the media. Each accepts children and className.

PartRole
Dropdown.ItemContainerWraps the media and text block of a row.
Dropdown.ItemContentStacks the label and description.
Dropdown.ItemLabelThe row's primary text.
Dropdown.ItemDescriptionThe secondary line beneath the label.
Dropdown.ItemIndicatorThe selection check shown in single/multi selection.