Dropdown Menu

Purpose and Scope

The Dropdown Menu component displays a set of actions or functions from a button-triggered menu. In shadcn/ui it is documented across three implementation bases: ARIA, Base UI, and Radix. Each base keeps the reader-facing goal the same, but the trigger and content structure follows the conventions of its underlying primitive library. Use this page when you need to choose the right import shape, install the correct dependency, structure groups and submenus, or understand how selection, destructive styling, and placement are represented in source-backed component contracts.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/content/docs/components/base/dropdown-menu.mdx, apps/v4/content/docs/components/radix/dropdown-menu.mdx

The docs position Dropdown Menu as a featured component and show the same core examples in each base: a demo with icons, shortcuts, and submenu items; a basic grouped menu; submenu nesting; keyboard shortcut hints; icon-enhanced labels; checkbox and radio-style choices; destructive actions; and richer account or complex examples. That consistency matters because shadcn/ui distributes component code that can be copied into an application, then customized locally. The public API is therefore not only a package import, but also a composition pattern that becomes part of the consuming project.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/content/docs/components/base/dropdown-menu.mdx, apps/v4/content/docs/components/radix/dropdown-menu.mdx, apps/v4/content/docs/changelog/2024-08-npx-shadcn-init.mdx

Relevant Source Files

  • apps/v4/content/docs/components/aria/dropdown-menu.mdx documents the ARIA Dropdown Menu page, including installation, usage, composition, and examples for groups, submenus, shortcuts, icons, selection, destructive items, avatar triggers, and complex menus.
  • apps/v4/content/docs/components/base/dropdown-menu.mdx documents the Base UI variant, including the DropdownMenuContent wrapper, render trigger pattern, checkbox items, radio groups, and the Base UI dependency.
  • apps/v4/content/docs/components/radix/dropdown-menu.mdx documents the Radix variant, including the asChild trigger pattern, DropdownMenuContent, checkbox items, radio groups, and the Radix dependency.
  • apps/v4/content/docs/components/aria/context-menu.mdx supplies closely related React Aria menu guidance for right-click menus, including logical placement in RTL layouts and submenu placement behavior.
  • apps/v4/registry/bases/aria/ui/dropdown-menu.tsx is the ARIA registry implementation for the local component file copied into projects, showing React Aria primitives, popover defaults, data slots, item variants, and selection-mode styling.
  • apps/v4/content/docs/changelog/2024-08-npx-shadcn-init.mdx explains the modern CLI distribution model, including npx shadcn add, framework-aware initialization, component-owned dependencies, aliases, and remote registry installation.

Installation and Base Selection

Install the component with the same CLI command regardless of base: npx shadcn@latest add dropdown-menu. The manual dependency changes by implementation. The ARIA page installs react-aria-components; the Base page installs @base-ui/react; the Radix page installs radix-ui. That difference is the first practical decision when using the component. If your project already standardizes on one primitive family, choose the matching docs page so the trigger props, content wrapper, and selection components align with the rest of your UI system.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/content/docs/components/base/dropdown-menu.mdx, apps/v4/content/docs/components/radix/dropdown-menu.mdx

npx shadcn@latest add dropdown-menu

Manual installation follows the same three-step shape across bases: install the primitive dependency, copy the generated components/ui/dropdown-menu.tsx source into the project, and update imports to match the local alias configuration. The changelog explains why this works as a distribution model: components can ship their own dependencies and the CLI can update project configuration instead of forcing a black-box package boundary. For Dropdown Menu, that means the local component can be inspected and changed while still starting from first-party defaults.

Sources: apps/v4/content/docs/changelog/2024-08-npx-shadcn-init.mdx, apps/v4/content/docs/components/aria/dropdown-menu.mdx

Core Usage and Composition

The ARIA usage pattern wraps the trigger button and menu content in DropdownMenuTrigger. The docs import Button, DropdownMenu, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, and DropdownMenuTrigger, then render a button followed by the menu body. In this base, DropdownMenu represents the popover-backed menu content rather than a root that separately contains DropdownMenuContent. This shape mirrors the visible ARIA implementation, where DropdownMenuTrigger maps to React Aria MenuTrigger and DropdownMenu renders a Popover containing a Menu.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/registry/bases/aria/ui/dropdown-menu.tsx

import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
 
<DropdownMenuTrigger>
  <Button variant="outline">Open</Button>
  <DropdownMenu>
    <DropdownMenuGroup>
      <DropdownMenuLabel>My Account</DropdownMenuLabel>
      <DropdownMenuItem>Profile</DropdownMenuItem>
      <DropdownMenuItem>Billing</DropdownMenuItem>
    </DropdownMenuGroup>
    <DropdownMenuSeparator />
    <DropdownMenuGroup>
      <DropdownMenuItem>Team</DropdownMenuItem>
      <DropdownMenuItem>Subscription</DropdownMenuItem>
    </DropdownMenuGroup>
  </DropdownMenu>
</DropdownMenuTrigger>

The Base and Radix variants introduce a root DropdownMenu with a separate DropdownMenuContent. In Base UI, DropdownMenuTrigger uses a render prop to render the button. In Radix, DropdownMenuTrigger uses asChild so the button becomes the interactive trigger while preserving the component’s behavior. Both variants show the same group, label, item, and separator structure inside content. When translating examples between bases, keep the visual organization but rewrite the trigger and content shell to match the primitive family.

Sources: apps/v4/content/docs/components/base/dropdown-menu.mdx, apps/v4/content/docs/components/radix/dropdown-menu.mdx

Item Patterns, Selection, and Destructive Actions

Dropdown Menu items are meant to be scanned quickly, so the docs emphasize labels, separators, icons, and shortcuts. A label introduces a group such as account actions; a separator divides unrelated groups; an icon helps identify frequent actions; and DropdownMenuShortcut presents keyboard hints without changing the action contract. Submenus are built with DropdownMenuSub, DropdownMenuSubTrigger, and DropdownMenuSubContent, which keeps secondary actions discoverable without flattening every option into the top-level menu.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/content/docs/components/base/dropdown-menu.mdx, apps/v4/content/docs/components/radix/dropdown-menu.mdx

Selection differs by base in the public examples. The ARIA docs use selectionMode="multiple" for checkbox-like toggles and selectionMode="single" for radio-like exclusive choices. The Base and Radix docs expose more specialized component names: DropdownMenuCheckboxItem, DropdownMenuRadioGroup, and DropdownMenuRadioItem. The ARIA implementation explains the bridge: item styling is selected from a cva variant keyed by the React Aria selectionMode, producing different classes for none, single, and multiple. The rendered item indicator also changes its data slot for radio versus checkbox selection.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/content/docs/components/base/dropdown-menu.mdx, apps/v4/content/docs/components/radix/dropdown-menu.mdx, apps/v4/registry/bases/aria/ui/dropdown-menu.tsx

Use variant="destructive" for irreversible or high-risk actions. The docs include destructive examples for the menu, and the ARIA implementation exposes variant?: "default" | "destructive" on DropdownMenuItem. That prop is written to a data attribute, which allows the copied component stylesheet to style destructive actions consistently. Prefer placing destructive actions in their own separated group, because the component’s visual treatment warns the user but does not replace careful information architecture or confirmation flows for truly irreversible operations.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/registry/bases/aria/ui/dropdown-menu.tsx

Implementation Details in the ARIA Registry

The ARIA registry file starts with "use client", imports React, cva, React Aria menu primitives, the shared cn utility, and an IconPlaceholder. The visible implementation maps shadcn/ui component names onto React Aria primitives while adding data slots and class names used by the registry styles. DropdownMenuTrigger is a thin wrapper around MenuTriggerPrimitive with data-slot="dropdown-menu-trigger". DropdownMenuGroup wraps MenuSectionPrimitive, and DropdownMenuLabel wraps HeaderPrimitive while accepting an inset flag for indentation-aware styling.

Sources: apps/v4/registry/bases/aria/ui/dropdown-menu.tsx

DropdownMenu itself combines placement and content behavior. Its default data-slot is dropdown-menu-content; default placement is bottom start; default offset is 4; and default crossOffset is 0. It renders a React Aria PopoverPrimitive with menu content classes, then places a MenuPrimitive inside it. This design is why the ARIA docs do not need a separate DropdownMenuContent component in the usage example: the exported DropdownMenu is already the popover content and the menu list together.

Sources: apps/v4/registry/bases/aria/ui/dropdown-menu.tsx

DropdownMenuItem adds several important source-level behaviors. It accepts React Aria MenuItem props plus inset and variant, sets data-slot="dropdown-menu-item", derives textValue automatically when children are a plain string, and composes class names with React Aria render props. That automatic textValue is useful for accessibility and typeahead-style menu behavior because textual children do not require a repeated label prop. For non-string children, pass textValue explicitly so the primitive still has a stable text representation.

Sources: apps/v4/registry/bases/aria/ui/dropdown-menu.tsx

RTL and Placement Guidance

Dropdown Menu placement should be treated as logical layout, not only physical screen direction. The related ARIA Context Menu docs show the same React Aria menu family using placement="end" for a menu on the logical end side of the trigger in RTL contexts, and they point readers to the project RTL configuration guide. For dropdowns, this means you should prefer logical placements such as start and end when building menus that must work in both left-to-right and right-to-left interfaces, then test the actual trigger, submenu, and collision behavior in the target language direction.

Sources: apps/v4/content/docs/components/aria/context-menu.mdx, apps/v4/registry/bases/aria/ui/dropdown-menu.tsx

Compact API Reference

AreaARIA names and behaviorBase and Radix names and behavior
Install commandnpx shadcn@latest add dropdown-menuSame command
Manual dependencyreact-aria-componentsBase: @base-ui/react; Radix: radix-ui
TriggerDropdownMenuTrigger wraps Button and DropdownMenuBase uses DropdownMenuTrigger render={<Button />}; Radix uses DropdownMenuTrigger asChild
Content shellDropdownMenu renders popover plus menu contentDropdownMenuContent wraps the menu body
GroupingDropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparatorSame documented grouping names
Basic itemDropdownMenuItem with variant="default" or variant="destructive"DropdownMenuItem; destructive examples are documented
Multiple selectionselectionMode="multiple" on the ARIA menu modelDropdownMenuCheckboxItem
Single selectionselectionMode="single" on the ARIA menu modelDropdownMenuRadioGroup and DropdownMenuRadioItem
SubmenusDropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContentSame documented submenu names
ShortcutsDropdownMenuShortcut in examplesSame shortcut pattern in examples
PlacementARIA implementation defaults to bottom start, offset=4, crossOffset=0Follow the selected primitive library API

Testing Signals and Next Steps

When validating a Dropdown Menu implementation, check more than whether it opens. Confirm the chosen base import shape matches the copied component file, the trigger pattern is correct for that base, labels and separators create meaningful groups, submenu actions are not hidden unnecessarily, and selection state uses either ARIA selectionMode or the Base/Radix checkbox and radio components. Also test destructive items, keyboard shortcut presentation, icon alignment, disabled items, focus behavior, and RTL placement if the product supports right-to-left languages.

Sources: apps/v4/content/docs/components/aria/dropdown-menu.mdx, apps/v4/content/docs/components/base/dropdown-menu.mdx, apps/v4/content/docs/components/radix/dropdown-menu.mdx, apps/v4/content/docs/components/aria/context-menu.mdx

Next, read the broader component-family pages for the base you selected, then compare Dialog and Context Menu if your interaction opens layered UI or right-click actions. If you are installing into an existing project, verify components.json aliases before copying examples, because the changelog notes that modern CLI projects align aliases for components, utils, UI, lib, and hooks. That alignment keeps imports like @/components/ui/dropdown-menu stable across generated components and local edits.

Sources: apps/v4/content/docs/changelog/2024-08-npx-shadcn-init.mdx