Dropdown menu
Contextual actions with shortcuts, checkable items, radio groups and submenus.
Playground
Menus hold actions on one object. Keep them under about ten items, put the most common first and the destructive one last, behind a separator.
Props
1import { ChevronDown, Copy, Pencil, Share2, Trash2 } from "lucide-react"2import { Button } from "@/components/ui/button"3import {4 DropdownMenu,5 DropdownMenuCheckboxItem,6 DropdownMenuContent,7 DropdownMenuGroup,8 DropdownMenuItem,9 DropdownMenuLabel,10 DropdownMenuSeparator,11 DropdownMenuShortcut,12 DropdownMenuSub,13 DropdownMenuSubContent,14 DropdownMenuSubTrigger,15 DropdownMenuTrigger,16} from "@/components/ui/dropdown-menu"1718<DropdownMenu>19 <DropdownMenuTrigger asChild>20 <Button variant="outline">21 Project <ChevronDown data-icon="inline-end" />22 </Button>23 </DropdownMenuTrigger>24 <DropdownMenuContent className="w-56">25 <DropdownMenuLabel>Northwind portal</DropdownMenuLabel>26 <DropdownMenuGroup>27 <DropdownMenuItem>28 <Pencil /> Rename29 <DropdownMenuShortcut>⌘R</DropdownMenuShortcut>30 </DropdownMenuItem>31 <DropdownMenuItem>32 <Copy /> Duplicate33 <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>34 </DropdownMenuItem>35 <DropdownMenuSub>36 <DropdownMenuSubTrigger>37 <Share2 /> Share38 </DropdownMenuSubTrigger>39 <DropdownMenuSubContent>40 <DropdownMenuItem>Copy link</DropdownMenuItem>41 <DropdownMenuItem>Invite people…</DropdownMenuItem>42 <DropdownMenuItem>Export as PDF</DropdownMenuItem>43 </DropdownMenuSubContent>44 </DropdownMenuSub>45 </DropdownMenuGroup>46 <DropdownMenuSeparator />47 <DropdownMenuLabel>Show</DropdownMenuLabel>48 <DropdownMenuCheckboxItem checked={completed} onCheckedChange={setCompleted}>49 Completed tasks50 </DropdownMenuCheckboxItem>51 <DropdownMenuCheckboxItem checked={subtasks} onCheckedChange={setSubtasks}>52 Subtasks53 </DropdownMenuCheckboxItem>54 <DropdownMenuSeparator />55 <DropdownMenuItem variant="destructive">56 <Trash2 /> Delete project57 <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>58 </DropdownMenuItem>59 </DropdownMenuContent>60</DropdownMenu>Anatomy
The open state, drawn in place so every part can be inspected. The trigger keeps its pressed look through aria-expanded while the menu is open.
DropdownMenuTriggerAny button via asChild. Gets aria-expanded and aria-haspopup.DropdownMenuLabelNon-interactive heading for a group.DropdownMenuItemHighlighted on hover or arrow keys; Enter selects.DropdownMenuShortcutHint only. Wire the shortcut separately.DropdownMenuCheckboxItemToggles with a check on the right.DropdownMenuSubTriggerOpens a submenu with → or hover.DropdownMenuSeparatorHairline between groups.Item variant="destructive"Last, after a separator, and confirmed.
States
States of the trigger. Open is the aria-expanded style shown in Anatomy; items have their own highlighted, checked and disabled states.
- Default
rest - Hover
:hover - Focus
:focus-visible - Loading
aria-busy - Disabled
disabled - Error
aria-invalid - Success
data-state=success
Patterns
Row actions with a submenu and a confirm step before deleting, and a view menu whose checkbox and radio items change the list as you toggle them.
Customer portal
Northwind
Billing migration
Acme Corporation
Onboarding emails
Globex
Open deals 4
Keyboard
- Open and focus the first item
- EnterorSpaceor↓
- Move between items
- ↑or↓
- Open a submenu
- →
- Close the submenu
- ←
- Typeahead to an item
- A–Z
- Close and return focus
- Esc
Semantics and ARIA
- The trigger gets
aria-haspopup="menu"andaria-expanded; the content is amenuofmenuitem,menuitemcheckboxandmenuitemradio. - Focus moves into the menu on open and returns to the trigger on close. Use
onCloseAutoFocusto redirect it, as Rename does to focus its input. - Icon-only triggers need an
aria-labelthat names the object, e.g. “Actions for Customer portal”, not just “More”. - Shortcut hints are visual only. The shortcut must work elsewhere, and should not be the only way to reach the action.
- Menus are for actions and settings. For picking a value in a form use Select; for navigation use links.
- Destructive items are never the first item, are confirmed before they run and are announced through the toast region.