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.mdxdocuments 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.mdxdocuments the Base UI variant, including theDropdownMenuContentwrapper,rendertrigger pattern, checkbox items, radio groups, and the Base UI dependency.apps/v4/content/docs/components/radix/dropdown-menu.mdxdocuments the Radix variant, including theasChildtrigger pattern,DropdownMenuContent, checkbox items, radio groups, and the Radix dependency.apps/v4/content/docs/components/aria/context-menu.mdxsupplies 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.tsxis 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.mdxexplains the modern CLI distribution model, includingnpx 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-menuManual 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
| Area | ARIA names and behavior | Base and Radix names and behavior |
|---|---|---|
| Install command | npx shadcn@latest add dropdown-menu | Same command |
| Manual dependency | react-aria-components | Base: @base-ui/react; Radix: radix-ui |
| Trigger | DropdownMenuTrigger wraps Button and DropdownMenu | Base uses DropdownMenuTrigger render={<Button />}; Radix uses DropdownMenuTrigger asChild |
| Content shell | DropdownMenu renders popover plus menu content | DropdownMenuContent wraps the menu body |
| Grouping | DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator | Same documented grouping names |
| Basic item | DropdownMenuItem with variant="default" or variant="destructive" | DropdownMenuItem; destructive examples are documented |
| Multiple selection | selectionMode="multiple" on the ARIA menu model | DropdownMenuCheckboxItem |
| Single selection | selectionMode="single" on the ARIA menu model | DropdownMenuRadioGroup and DropdownMenuRadioItem |
| Submenus | DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent | Same documented submenu names |
| Shortcuts | DropdownMenuShortcut in examples | Same shortcut pattern in examples |
| Placement | ARIA implementation defaults to bottom start, offset=4, crossOffset=0 | Follow 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