Components

Base Components

Dropdown Menu

A menu triggered by a button, with items and optional submenus.

Example

Installation

Install the following dependencies:

npm install radix-uinpm install lucide-react

Create a dropdown-menu.tsx file and paste the following code into it.

"use client"import * as React from "react"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"import { cn } from "@/lib/utils"function DropdownMenu({  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {  return (    <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />  )}function DropdownMenuTrigger({  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {  return (    <DropdownMenuPrimitive.Trigger      data-slot="dropdown-menu-trigger"      {...props}    />  )}function DropdownMenuGroup({  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {  return (    <DropdownMenuPrimitive.Group      data-slot="dropdown-menu-group"      {...props}    />  )}function DropdownMenuPortal({  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {  return (    <DropdownMenuPrimitive.Portal      data-slot="dropdown-menu-portal"      {...props}    />  )}function DropdownMenuSub({  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {  return (    <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />  )}function DropdownMenuRadioGroup({  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {  return (    <DropdownMenuPrimitive.RadioGroup      data-slot="dropdown-menu-radio-group"      {...props}    />  )}function DropdownMenuSubTrigger({  className,  inset,  children,  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {  inset?: boolean}) {  return (    <DropdownMenuPrimitive.SubTrigger      data-slot="dropdown-menu-sub-trigger"      data-inset={inset}      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-primary flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      {...props}    >      {children}      <ChevronRightIcon className="ml-auto" />    </DropdownMenuPrimitive.SubTrigger>  )}function DropdownMenuSubContent({  className,  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {  return (    <DropdownMenuPrimitive.SubContent      data-slot="dropdown-menu-sub-content"      className={cn(        "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 z-[210] min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",        className      )}      {...props}    />  )}function DropdownMenuContent({  className,  sideOffset = 4,  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Content> & {  dir?: React.HTMLAttributes<HTMLDivElement>["dir"]}) {  return (    <DropdownMenuPrimitive.Portal>      <DropdownMenuPrimitive.Content        data-slot="dropdown-menu-content"        sideOffset={sideOffset}        className={cn(          "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 z-[210] max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",          className        )}        {...props}      />    </DropdownMenuPrimitive.Portal>  )}function DropdownMenuItem({  className,  inset,  variant = "default",  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {  inset?: boolean  variant?: "default" | "destructive"}) {  return (    <DropdownMenuPrimitive.Item      data-slot="dropdown-menu-item"      data-inset={inset}      data-variant={variant}      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-primary relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      {...props}    />  )}function DropdownMenuCheckboxItem({  className,  children,  checked,  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {  return (    <DropdownMenuPrimitive.CheckboxItem      data-slot="dropdown-menu-checkbox-item"      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      checked={checked}      {...props}    >      <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">        <DropdownMenuPrimitive.ItemIndicator>          <CheckIcon className="size-4" />        </DropdownMenuPrimitive.ItemIndicator>      </span>      {children}    </DropdownMenuPrimitive.CheckboxItem>  )}function DropdownMenuRadioItem({  className,  children,  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {  return (    <DropdownMenuPrimitive.RadioItem      data-slot="dropdown-menu-radio-item"      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      {...props}    >      <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">        <DropdownMenuPrimitive.ItemIndicator>          <CircleIcon className="size-2 fill-current" />        </DropdownMenuPrimitive.ItemIndicator>      </span>      {children}    </DropdownMenuPrimitive.RadioItem>  )}function DropdownMenuLabel({  className,  inset,  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {  inset?: boolean}) {  return (    <DropdownMenuPrimitive.Label      data-slot="dropdown-menu-label"      data-inset={inset}      className={cn(        "text-menu-heading px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",        className      )}      {...props}    />  )}function DropdownMenuSeparator({  className,  ...props}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {  return (    <DropdownMenuPrimitive.Separator      data-slot="dropdown-menu-separator"      className={cn("bg-border -mx-1 my-1 h-px", className)}      {...props}    />  )}function DropdownMenuShortcut({  className,  ...props}: React.ComponentProps<"span">) {  return (    <span      data-slot="dropdown-menu-shortcut"      className={cn(        "text-primary ml-auto text-xs tracking-widest",        className      )}      {...props}    />  )}export {  DropdownMenu,  DropdownMenuTrigger,  DropdownMenuContent,  DropdownMenuItem,  DropdownMenuCheckboxItem,  DropdownMenuRadioItem,  DropdownMenuLabel,  DropdownMenuSeparator,  DropdownMenuShortcut,  DropdownMenuGroup,  DropdownMenuPortal,  DropdownMenuSub,  DropdownMenuSubContent,  DropdownMenuSubTrigger,  DropdownMenuRadioGroup,}

Check the import paths to ensure they match your project setup.

Usage

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

Examples

Basic

A basic dropdown with labels and separators.
Use DropdownMenuSub, DropdownMenuSubTrigger, and DropdownMenuSubContent for nested actions.

Shortcuts

Add DropdownMenuShortcut for keyboard hints.

Icons

Pair icons with labels for faster scanning.

Checkboxes

Use DropdownMenuCheckboxItem with checked and onCheckedChange for toggles.

Checkboxes with icons

Icons work inside checkbox items as well.

Radio group

Use DropdownMenuRadioGroup and DropdownMenuRadioItem for a single choice.

Radio with icons

Radio items can include leading icons (for example payment methods).

Destructive

Use variant="destructive" on DropdownMenuItem for dangerous actions.

Avatar trigger

Use a circular avatar (or icon-only button) as the trigger for an account menu.

Complex

Combine groups, icons, a submenu, a checkbox, and a destructive action.

RTL

Right-to-left layout: wrap the trigger and menu in a container with dir="rtl".

API Reference

The dropdown composes Radix primitives: DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, and DropdownMenuSubContent. See the Radix Dropdown Menu documentation for behavior and accessibility.

On this page