# Dropdown Menu
URL: /design/components/dropdown-menu

Actions behind a trigger: items, shortcuts, and separators on a quiet surface.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

\[interactive preview component DropdownMenuSpecimen omitted]

Code for DropdownMenuSpecimen preview:

```tsx
"use client";

import { useState, type ReactNode } from "react";
import {
  ChevronDownIcon,
  ChevronsUpDownIcon,
  CopyIcon,
  LogOutIcon,
  PlusIcon,
  RefreshCwIcon,
  SettingsIcon,
  UserIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

function DropdownMenuSpecimen(): ReactNode {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <Button variant="outline">
            Open menu
            <ChevronDownIcon className="size-3.5" />
          </Button>
        }
      />
      <DropdownMenuContent align="start">
        <DropdownMenuItem>
          <UserIcon className="size-4" />
          Profile
        </DropdownMenuItem>
        <DropdownMenuItem>
          <SettingsIcon className="size-4" />
          Settings
          <DropdownMenuShortcut>⌘,</DropdownMenuShortcut>
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem>
          <LogOutIcon className="size-4" />
          Sign out
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}
```

## Installation

Install the dependencies:

- packages

  - @base-ui/react

Copy the source into `components/ui/dropdown-menu.tsx`. Registry items that depend on it install it automatically.

- code

  "use client"; import \* as React from "react"; import { Menu as MenuPrimitive } from "@base-ui/react/menu"; import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; import { cn } from "@/lib/utils"; function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) { return \<MenuPrimitive.Root data-slot="dropdown-menu" {...props} />; } function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) { return \<MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />; } function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) { return \<MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />; } function DropdownMenuContent({ align = "start", alignOffset = 0, side = "bottom", sideOffset = 4, className, ...props }: MenuPrimitive.Popup.Props & Pick< MenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" >) { return ( \<MenuPrimitive.Portal> \<MenuPrimitive.Positioner className="isolate z-50 outline-none" align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} > \<MenuPrimitive.Popup data-slot="dropdown-menu-content" className={cn( "bg-popover text-popover-foreground data-\[side=bottom]:slide-in-from-top-2 data-\[side=inline-end]:slide-in-from-left-2 data-\[side=inline-start]:slide-in-from-right-2 data-\[side=left]:slide-in-from-right-2 data-\[side=right]:slide-in-from-left-2 data-\[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 ring-foreground/10 z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-\[var(--radius-surface,var(--radius-lg))] p-1.5 ring-1 duration-100 outline-none data-closed:overflow-hidden", className, )} {...props} /> \</MenuPrimitive.Positioner> \</MenuPrimitive.Portal> ); } function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) { return \<MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />; } function DropdownMenuLabel({ className, inset, ...props }: MenuPrimitive.GroupLabel.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.GroupLabel data-slot="dropdown-menu-label" data-inset={inset} className={cn( "text-muted-foreground px-2 py-1.5 font-mono text-\[11px] font-medium tracking-wide uppercase data-inset:pl-7", className, )} {...props} /> ); } function DropdownMenuItem({ className, inset, variant = "default", ...props }: MenuPrimitive.Item.Props & { inset?: boolean; variant?: "default" | "destructive"; }) { return ( \<MenuPrimitive.Item data-slot="dropdown-menu-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-foreground/\[0.06] data-\[variant=destructive]:text-destructive data-\[variant=destructive]:focus:bg-destructive/10 data-\[variant=destructive]:focus:text-destructive dark:data-\[variant=destructive]:focus:bg-destructive/20 data-\[variant=destructive]:\*:\[svg]:text-destructive group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} /> ); } function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) { return \<MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />; } function DropdownMenuSubTrigger({ className, inset, children, ...props }: MenuPrimitive.SubmenuTrigger.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.SubmenuTrigger data-slot="dropdown-menu-sub-trigger" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] data-open:bg-foreground/\[0.06] data-popup-open:bg-foreground/\[0.06] flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} > {children} \<ChevronRightIcon className="ms-auto size-4 rtl:rotate-180" /> \</MenuPrimitive.SubmenuTrigger> ); } function DropdownMenuSubContent({ align = "start", alignOffset = -3, side = "right", sideOffset = 0, className, ...props }: React.ComponentProps\<typeof DropdownMenuContent>) { return ( \<DropdownMenuContent data-slot="dropdown-menu-sub-content" className={cn( "bg-popover text-popover-foreground data-\[side=bottom]:slide-in-from-top-2 data-\[side=left]:slide-in-from-right-2 data-\[side=right]:slide-in-from-left-2 data-\[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 ring-foreground/10 w-auto min-w-\[96px] rounded-\[var(--radius-surface,var(--radius-lg))] p-1 ring-1 duration-100", className, )} align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} {...props} /> ); } function DropdownMenuCheckboxItem({ className, children, checked, inset, ...props }: MenuPrimitive.CheckboxItem.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.CheckboxItem data-slot="dropdown-menu-checkbox-item" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} checked={checked} {...props} > \<span className="pointer-events-none absolute right-2 flex items-center justify-center" data-slot="dropdown-menu-checkbox-item-indicator" > \<MenuPrimitive.CheckboxItemIndicator> \<CheckIcon className="size-4" /> \</MenuPrimitive.CheckboxItemIndicator> \</span> {children} \</MenuPrimitive.CheckboxItem> ); } function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) { return ( \<MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} /> ); } function DropdownMenuRadioItem({ className, children, inset, ...props }: MenuPrimitive.RadioItem.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.RadioItem data-slot="dropdown-menu-radio-item" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} > \<span className="pointer-events-none absolute right-2 flex items-center justify-center" data-slot="dropdown-menu-radio-item-indicator" > \<MenuPrimitive.RadioItemIndicator> \<CircleIcon className="size-2 fill-current" /> \</MenuPrimitive.RadioItemIndicator> \</span> {children} \</MenuPrimitive.RadioItem> ); } function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) { return ( \<MenuPrimitive.Separator data-slot="dropdown-menu-separator" className={cn("bg-foreground/10 -mx-1.5 my-1 h-px", className)} {...props} /> ); } function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { return ( \<span data-slot="dropdown-menu-shortcut" className={cn( "text-muted-foreground ml-auto font-mono text-\[11px] tracking-wider", className, )} {...props} /> ); } export { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, };

* title

  components/ui/dropdown-menu.tsx

* copyText

  "use client"; import \* as React from "react"; import { Menu as MenuPrimitive } from "@base-ui/react/menu"; import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; import { cn } from "@/lib/utils"; function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) { return \<MenuPrimitive.Root data-slot="dropdown-menu" {...props} />; } function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) { return \<MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />; } function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) { return \<MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />; } function DropdownMenuContent({ align = "start", alignOffset = 0, side = "bottom", sideOffset = 4, className, ...props }: MenuPrimitive.Popup.Props & Pick< MenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" >) { return ( \<MenuPrimitive.Portal> \<MenuPrimitive.Positioner className="isolate z-50 outline-none" align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} > \<MenuPrimitive.Popup data-slot="dropdown-menu-content" className={cn( "bg-popover text-popover-foreground data-\[side=bottom]:slide-in-from-top-2 data-\[side=inline-end]:slide-in-from-left-2 data-\[side=inline-start]:slide-in-from-right-2 data-\[side=left]:slide-in-from-right-2 data-\[side=right]:slide-in-from-left-2 data-\[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 ring-foreground/10 z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-\[var(--radius-surface,var(--radius-lg))] p-1.5 ring-1 duration-100 outline-none data-closed:overflow-hidden", className, )} {...props} /> \</MenuPrimitive.Positioner> \</MenuPrimitive.Portal> ); } function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) { return \<MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />; } function DropdownMenuLabel({ className, inset, ...props }: MenuPrimitive.GroupLabel.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.GroupLabel data-slot="dropdown-menu-label" data-inset={inset} className={cn( "text-muted-foreground px-2 py-1.5 font-mono text-\[11px] font-medium tracking-wide uppercase data-inset:pl-7", className, )} {...props} /> ); } function DropdownMenuItem({ className, inset, variant = "default", ...props }: MenuPrimitive.Item.Props & { inset?: boolean; variant?: "default" | "destructive"; }) { return ( \<MenuPrimitive.Item data-slot="dropdown-menu-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-foreground/\[0.06] data-\[variant=destructive]:text-destructive data-\[variant=destructive]:focus:bg-destructive/10 data-\[variant=destructive]:focus:text-destructive dark:data-\[variant=destructive]:focus:bg-destructive/20 data-\[variant=destructive]:\*:\[svg]:text-destructive group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} /> ); } function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) { return \<MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />; } function DropdownMenuSubTrigger({ className, inset, children, ...props }: MenuPrimitive.SubmenuTrigger.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.SubmenuTrigger data-slot="dropdown-menu-sub-trigger" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] data-open:bg-foreground/\[0.06] data-popup-open:bg-foreground/\[0.06] flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} > {children} \<ChevronRightIcon className="ms-auto size-4 rtl:rotate-180" /> \</MenuPrimitive.SubmenuTrigger> ); } function DropdownMenuSubContent({ align = "start", alignOffset = -3, side = "right", sideOffset = 0, className, ...props }: React.ComponentProps\<typeof DropdownMenuContent>) { return ( \<DropdownMenuContent data-slot="dropdown-menu-sub-content" className={cn( "bg-popover text-popover-foreground data-\[side=bottom]:slide-in-from-top-2 data-\[side=left]:slide-in-from-right-2 data-\[side=right]:slide-in-from-left-2 data-\[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 ring-foreground/10 w-auto min-w-\[96px] rounded-\[var(--radius-surface,var(--radius-lg))] p-1 ring-1 duration-100", className, )} align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} {...props} /> ); } function DropdownMenuCheckboxItem({ className, children, checked, inset, ...props }: MenuPrimitive.CheckboxItem.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.CheckboxItem data-slot="dropdown-menu-checkbox-item" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} checked={checked} {...props} > \<span className="pointer-events-none absolute right-2 flex items-center justify-center" data-slot="dropdown-menu-checkbox-item-indicator" > \<MenuPrimitive.CheckboxItemIndicator> \<CheckIcon className="size-4" /> \</MenuPrimitive.CheckboxItemIndicator> \</span> {children} \</MenuPrimitive.CheckboxItem> ); } function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) { return ( \<MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} /> ); } function DropdownMenuRadioItem({ className, children, inset, ...props }: MenuPrimitive.RadioItem.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.RadioItem data-slot="dropdown-menu-radio-item" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} > \<span className="pointer-events-none absolute right-2 flex items-center justify-center" data-slot="dropdown-menu-radio-item-indicator" > \<MenuPrimitive.RadioItemIndicator> \<CircleIcon className="size-2 fill-current" /> \</MenuPrimitive.RadioItemIndicator> \</span> {children} \</MenuPrimitive.RadioItem> ); } function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) { return ( \<MenuPrimitive.Separator data-slot="dropdown-menu-separator" className={cn("bg-foreground/10 -mx-1.5 my-1 h-px", className)} {...props} /> ); } function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { return ( \<span data-slot="dropdown-menu-shortcut" className={cn( "text-muted-foreground ml-auto font-mono text-\[11px] tracking-wider", className, )} {...props} /> ); } export { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, };

* viewportClassName

  max-h-\[450px]

- language

  tsx

- code

  "use client"; import \* as React from "react"; import { Menu as MenuPrimitive } from "@base-ui/react/menu"; import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; import { cn } from "@/lib/utils"; function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) { return \<MenuPrimitive.Root data-slot="dropdown-menu" {...props} />; } function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) { return \<MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />; } function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) { return \<MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />; } function DropdownMenuContent({ align = "start", alignOffset = 0, side = "bottom", sideOffset = 4, className, ...props }: MenuPrimitive.Popup.Props & Pick< MenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" >) { return ( \<MenuPrimitive.Portal> \<MenuPrimitive.Positioner className="isolate z-50 outline-none" align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} > \<MenuPrimitive.Popup data-slot="dropdown-menu-content" className={cn( "bg-popover text-popover-foreground data-\[side=bottom]:slide-in-from-top-2 data-\[side=inline-end]:slide-in-from-left-2 data-\[side=inline-start]:slide-in-from-right-2 data-\[side=left]:slide-in-from-right-2 data-\[side=right]:slide-in-from-left-2 data-\[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 ring-foreground/10 z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-\[var(--radius-surface,var(--radius-lg))] p-1.5 ring-1 duration-100 outline-none data-closed:overflow-hidden", className, )} {...props} /> \</MenuPrimitive.Positioner> \</MenuPrimitive.Portal> ); } function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) { return \<MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />; } function DropdownMenuLabel({ className, inset, ...props }: MenuPrimitive.GroupLabel.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.GroupLabel data-slot="dropdown-menu-label" data-inset={inset} className={cn( "text-muted-foreground px-2 py-1.5 font-mono text-\[11px] font-medium tracking-wide uppercase data-inset:pl-7", className, )} {...props} /> ); } function DropdownMenuItem({ className, inset, variant = "default", ...props }: MenuPrimitive.Item.Props & { inset?: boolean; variant?: "default" | "destructive"; }) { return ( \<MenuPrimitive.Item data-slot="dropdown-menu-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-foreground/\[0.06] data-\[variant=destructive]:text-destructive data-\[variant=destructive]:focus:bg-destructive/10 data-\[variant=destructive]:focus:text-destructive dark:data-\[variant=destructive]:focus:bg-destructive/20 data-\[variant=destructive]:\*:\[svg]:text-destructive group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} /> ); } function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) { return \<MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />; } function DropdownMenuSubTrigger({ className, inset, children, ...props }: MenuPrimitive.SubmenuTrigger.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.SubmenuTrigger data-slot="dropdown-menu-sub-trigger" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] data-open:bg-foreground/\[0.06] data-popup-open:bg-foreground/\[0.06] flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} > {children} \<ChevronRightIcon className="ms-auto size-4 rtl:rotate-180" /> \</MenuPrimitive.SubmenuTrigger> ); } function DropdownMenuSubContent({ align = "start", alignOffset = -3, side = "right", sideOffset = 0, className, ...props }: React.ComponentProps\<typeof DropdownMenuContent>) { return ( \<DropdownMenuContent data-slot="dropdown-menu-sub-content" className={cn( "bg-popover text-popover-foreground data-\[side=bottom]:slide-in-from-top-2 data-\[side=left]:slide-in-from-right-2 data-\[side=right]:slide-in-from-left-2 data-\[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 ring-foreground/10 w-auto min-w-\[96px] rounded-\[var(--radius-surface,var(--radius-lg))] p-1 ring-1 duration-100", className, )} align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} {...props} /> ); } function DropdownMenuCheckboxItem({ className, children, checked, inset, ...props }: MenuPrimitive.CheckboxItem.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.CheckboxItem data-slot="dropdown-menu-checkbox-item" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} checked={checked} {...props} > \<span className="pointer-events-none absolute right-2 flex items-center justify-center" data-slot="dropdown-menu-checkbox-item-indicator" > \<MenuPrimitive.CheckboxItemIndicator> \<CheckIcon className="size-4" /> \</MenuPrimitive.CheckboxItemIndicator> \</span> {children} \</MenuPrimitive.CheckboxItem> ); } function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) { return ( \<MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} /> ); } function DropdownMenuRadioItem({ className, children, inset, ...props }: MenuPrimitive.RadioItem.Props & { inset?: boolean; }) { return ( \<MenuPrimitive.RadioItem data-slot="dropdown-menu-radio-item" data-inset={inset} className={cn( "focus:bg-foreground/\[0.06] relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 \[&\_svg]:pointer-events-none \[&\_svg]:shrink-0 \[&\_svg:not(\[class\*='size-'])]:size-4", className, )} {...props} > \<span className="pointer-events-none absolute right-2 flex items-center justify-center" data-slot="dropdown-menu-radio-item-indicator" > \<MenuPrimitive.RadioItemIndicator> \<CircleIcon className="size-2 fill-current" /> \</MenuPrimitive.RadioItemIndicator> \</span> {children} \</MenuPrimitive.RadioItem> ); } function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) { return ( \<MenuPrimitive.Separator data-slot="dropdown-menu-separator" className={cn("bg-foreground/10 -mx-1.5 my-1 h-px", className)} {...props} /> ); } function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { return ( \<span data-slot="dropdown-menu-shortcut" className={cn( "text-muted-foreground ml-auto font-mono text-\[11px] tracking-wider", className, )} {...props} /> ); } export { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, };

## Usage

```
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";

export function Example() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Open</Button>} />
      <DropdownMenuContent>
        <DropdownMenuItem>Profile</DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem>Sign out</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}
```

## Examples

### Checkboxes and submenus

`DropdownMenuCheckboxItem` holds a checked state, `DropdownMenuLabel` titles a group, and `DropdownMenuSub` nests a second level.

\[interactive preview component DropdownMenuChecklistSpecimen omitted]

Code for DropdownMenuChecklistSpecimen preview:

```tsx
"use client";

import { useState, type ReactNode } from "react";
import {
  ChevronDownIcon,
  ChevronsUpDownIcon,
  CopyIcon,
  LogOutIcon,
  PlusIcon,
  RefreshCwIcon,
  SettingsIcon,
  UserIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

function DropdownMenuChecklistSpecimen(): ReactNode {
  const [showTimestamps, setShowTimestamps] = useState(true);
  const [showAvatars, setShowAvatars] = useState(false);

  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <Button variant="outline">
            View
            <ChevronDownIcon className="size-3.5" />
          </Button>
        }
      />
      <DropdownMenuContent align="start">
        <DropdownMenuLabel>Show in thread</DropdownMenuLabel>
        <DropdownMenuCheckboxItem
          checked={showTimestamps}
          onCheckedChange={setShowTimestamps}
        >
          Timestamps
        </DropdownMenuCheckboxItem>
        <DropdownMenuCheckboxItem
          checked={showAvatars}
          onCheckedChange={setShowAvatars}
        >
          Avatars
        </DropdownMenuCheckboxItem>
        <DropdownMenuSeparator />
        <DropdownMenuSub>
          <DropdownMenuSubTrigger>Export</DropdownMenuSubTrigger>
          <DropdownMenuSubContent>
            <DropdownMenuItem>Markdown</DropdownMenuItem>
            <DropdownMenuItem>JSON</DropdownMenuItem>
          </DropdownMenuSubContent>
        </DropdownMenuSub>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}
```

## API Reference

The parts wrap Base UI's Menu primitives and accept their props.

### DropdownMenu

- `open?`: `boolean` — Controlled open state.
- `onOpenChange?`: `(open: boolean) => void` — Called when the open state changes.
- `defaultOpen`: `boolean` (default `false`) — Uncontrolled initial open state.

### DropdownMenuContent

- `align`: `"start" | "center" | "end"` (default `"center"`) — Alignment against the trigger.
- `sideOffset`: `number` (default `4`) — Distance from the trigger in pixels.

### DropdownMenuItem

- `onSelect?`: `() => void` — Called when the item is selected.
- `disabled`: `boolean` (default `false`) — Prevents selection and mutes the item.