Chuyển tới nội dung
Component

DropdownMenu

A list of actions behind a button: Rename, Duplicate, Delete. It opens on the raised surface with items the height and look of Select's options, and moves with the arrow keys. Items can carry a leading icon and a shortcut, turn options on and off, or pick one of several.

Xem trước

Props

  • open
  • defaultOpen
  • side
  • align
  • sideOffset
  • destructive
  • disabled
  • inset
  • shortcut
import { IconCopy, IconPencil, IconTrash } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Cách dùng

Khi nào dùng

  • Several actions on one item behind one button: Rename, Duplicate, Delete.
  • Options that turn on and off, or one of several, in a toolbar or a header.

Khi nào không dùng

  • Picking a value in a form. Use Select.
  • Fields or other controls. Use Popover.
  • The main action of a screen, or the only way to do a common action. Use Button.

Biến thể

side

Set on DropdownMenuContent. The side of the trigger it opens on. It flips when there is no room.

  • top

  • right

  • bottommặc định

  • left

import { IconCopy, IconPencil, IconTrash } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent side="top">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent side="right">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent side="left">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

align

Set on DropdownMenuContent. start lines the menu up with the trigger's start edge; end for a trigger at the end of a row.

  • startmặc định

  • center

  • end

import { IconCopy, IconPencil, IconTrash } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="center">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="end">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} weight="regular" />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} weight="regular" />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} weight="regular" />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Ví dụ

Actions

import { IconCopy, IconDots, IconPencil, IconTrash } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary" iconOnly aria-label="More actions">
      <IconDots size={16} />
    </Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="end">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Rename</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Delete project</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Groups and choices

A checkbox item turns an option on or off; radio items pick one. In an app, pair checked with onCheckedChange and value with onValueChange.

import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">View</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuLabel inset>Show</DropdownMenuLabel>
    <DropdownMenuCheckboxItem checked>Grid</DropdownMenuCheckboxItem>
    <DropdownMenuCheckboxItem>Rulers</DropdownMenuCheckboxItem>
    <DropdownMenuSeparator />
    <DropdownMenuLabel inset>Sort by</DropdownMenuLabel>
    <DropdownMenuRadioGroup value="edited">
      <DropdownMenuRadioItem value="edited">Last edited</DropdownMenuRadioItem>
      <DropdownMenuRadioItem value="name">Name</DropdownMenuRadioItem>
    </DropdownMenuRadioGroup>
  </DropdownMenuContent>
</DropdownMenu>

asChild makes a link the item, for actions that go to another page.

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

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Account</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem asChild>
      <a href="#profile">Profile</a>
    </DropdownMenuItem>
    <DropdownMenuItem asChild>
      <a href="#billing">Billing</a>
    </DropdownMenuItem>
    <DropdownMenuItem disabled>Team settings</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Nên và không nên

Nên

  • Start each item with a verb: Rename, Duplicate, Delete.
  • Put destructive actions last, after a separator, and confirm them with an AlertDialog.
  • Name an icon-only trigger with aria-label, such as More actions.

Không nên

  • Don't use it to pick a value in a form; use Select.
  • Don't put fields or other controls in it; use Popover.
  • Don't hide the only way to do a common action in a menu; give it a Button.

Props

TênKiểuGiá trịMặc địnhMô tả
openboolean--Set on DropdownMenu. Whether it is open, when you control it. Pair it with onOpenChange.
defaultOpenboolean-falseSet on DropdownMenu. Opens it on first render, when you don't control it.
onOpenChangefunction--Set on DropdownMenu. Called with true or false when it opens or closes.
modalboolean-trueSet on DropdownMenu. true keeps the rest of the page out of reach (no hover, no scroll) while the menu is open.
sideenumtop | right | bottom | leftbottomSet on DropdownMenuContent. The side of the trigger it opens on. It flips when there is no room.
alignenumstart | center | endstartSet on DropdownMenuContent. start lines the menu up with the trigger's start edge; end for a trigger at the end of a row.
sideOffsetnumber-4Set on DropdownMenuContent. Space between the trigger and the menu, in px. 4 is spacing-xs.
loopboolean-falseSet on DropdownMenuContent. The arrow keys wrap from the last item to the first.
destructiveboolean-falseSet on DropdownMenuItem. Danger text for an action that deletes or can't be undone. Confirm it with an AlertDialog.
disabledboolean-falseSet on an item. It can't be highlighted or run, and the arrow keys skip it.
insetboolean-falseSet on DropdownMenuItem or DropdownMenuLabel. Lines the label up with items that have an icon or a check.
leadingIconnode--Set on DropdownMenuItem. A decorative 16px icon before the label: <IconPencil size={16} />.
shortcutstring--Set on DropdownMenuItem. The keyboard shortcut at the end: ⌘D. The app handles the key itself.
asChildboolean-falseSet on DropdownMenuItem. Renders the child (a link) as the item, for actions that go to another page. leadingIcon and shortcut don't apply; put the icon inside the link.

Slot

TênBắt buộcMô tả
triggercóDropdownMenuTrigger with asChild around a Button.
contentcóDropdownMenuContent with one DropdownMenuItem per action, in the order users need them, destructive ones last. Group long menus with DropdownMenuLabel and DropdownMenuSeparator.

Cấu tạo

PhầnMô tả
rootDropdownMenuItem: one action. The md control height (32px on mouse, 36px on touch), inner corners, 14px primary text, a leading icon in the primary icon color, the neutral hover overlay when highlighted. destructive turns the text and icon to the danger text color.
destructiveA destructive DropdownMenuItem (destructive): danger text on the same neutral row and highlight. Classes land on the item.
destructiveIconThe leading icon of a destructive item, in the danger text color (there is no danger icon token).
menuDropdownMenu. Holds the open state; renders nothing itself.
triggerDropdownMenuTrigger: the button that opens the menu, usually a Button with asChild.
contentDropdownMenuContent: the floating list on the raised surface, at least 192px wide, the same surface as Select's list. It scrolls when it is taller than the screen minus spacing-sm at the top and bottom.
iconThe leading icon of an item (leadingIcon), Tabler icons, 16px.
indicatorThe check of a DropdownMenuCheckboxItem (Tabler check, 16px) or the 6px dot of a DropdownMenuRadioItem, before the label.
groupLabelDropdownMenuLabel: the heading of a group, one step smaller than an item, in secondary text.
separatorDropdownMenuSeparator: a line across the full menu between two groups.
shortcutThe shortcut at the end of an item (shortcut or DropdownMenuShortcut): 12px mono in tertiary text.

Khả năng truy cập

Role: menu

PhímHành động
Space, Enter, ArrowDownOn the trigger: opens the menu and focuses the first item.
ArrowUp, ArrowDownMoves between items, skipping disabled ones. With loop, it wraps from the last to the first.
Home, EndFocuses the first or the last item.
Enter, SpaceRuns the item and closes the menu. On a checkbox or radio item, turns it on or picks it.
EscapeCloses the menu and returns focus to the trigger.
A letterFocuses the next item whose label starts with it.
  • The trigger gets aria-haspopup and aria-expanded; the list is a menu of menuitem, menuitemcheckbox and menuitemradio.
  • Name an icon-only trigger with aria-label: More actions.
  • A destructive item says what it destroys (Delete project) and opens an AlertDialog; danger text is not the only warning.
  • The shortcut text is read with the label. The app handles the shortcut itself; the menu only shows it.
  • A group heading (DropdownMenuLabel) is not focusable.

Cài đặt

npx shadcn add https://werewolf-ui.vercel.app/r/dropdown-menu.json

Lệnh này thêm luôn styles/werewolf.css, bộ token mà mọi component dùng, và các component khác mà nó cần. Import file đó một lần trong CSS gốc, ngay sau @import "tailwindcss", với đường dẫn tính từ file CSS đó (từ app/globals.css là @import "../styles/werewolf.css").