Chuyển tới nội dung

Pro đang mở bán trước. Cài đặt mở từ tháng 1/2027. Xem Pro

Component

DropdownMenu

Danh sách hành động phía sau một button: Đổi tên, Nhân bản, Xóa. Nó mở trên bề mặt raised, các mục có chiều cao và vẻ như option của Select, và đi bằng các phím mũi tên. Mục có thể mang icon đầu và một shortcut, bật hoặc tắt lựa chọn, hoặc chọn một trong nhiều.

  • npm: 2 trực tiếp, 4 tổng
  • registry: 3 trực tiếp, 3 tổng

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">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Cách dùng

Khi nào dùng

  • Nhiều hành động trên một mục, phía sau một button: Đổi tên, Nhân bản, Xóa.
  • Các lựa chọn bật hoặc tắt, hoặc một trong nhiều, trong thanh công cụ hoặc header.

Khi nào không dùng

  • Chọn một giá trị trong form. Dùng Select.
  • Field hoặc các control khác. Dùng Popover.
  • Hành động chính của một màn hình, hoặc cách duy nhất để làm một hành động thường gặp. Dùng Button.

Biến thể

side

Đặt trên DropdownMenuContent. Phía của trigger mà nó mở vào. Nó lật khi không đủ chỗ.

  • 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">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent side="top">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent side="right">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent side="left">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

align

Đặt trên DropdownMenuContent. start căn menu với mép đầu của trigger; end cho trigger ở cuối một hàng.

  • 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">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="center">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Tùy chọn</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="end">
    <DropdownMenuItem leadingIcon={<IconPencil size={16} />}>Đổi tên</DropdownMenuItem>
    <DropdownMenuItem leadingIcon={<IconCopy size={16} />} shortcut="⌘D">Nhân bản</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem destructive leadingIcon={<IconTrash size={16} />}>Xóa dự án</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Ví dụ

Hành động

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="Thêm thao tác">
      <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>

Nhóm và lựa chọn

Mục checkbox bật hoặc tắt một lựa chọn; các mục radio chọn một. Trong ứng dụng, ghép checked với onCheckedChange và value với 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">Xem</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuLabel inset>Hiện</DropdownMenuLabel>
    <DropdownMenuCheckboxItem checked>Lưới</DropdownMenuCheckboxItem>
    <DropdownMenuCheckboxItem>Thước kẻ</DropdownMenuCheckboxItem>
    <DropdownMenuSeparator />
    <DropdownMenuLabel inset>Sắp xếp theo</DropdownMenuLabel>
    <DropdownMenuRadioGroup value="edited">
      <DropdownMenuRadioItem value="edited">Chỉnh sửa lần cuối</DropdownMenuRadioItem>
      <DropdownMenuRadioItem value="name">Tên</DropdownMenuRadioItem>
    </DropdownMenuRadioGroup>
  </DropdownMenuContent>
</DropdownMenu>

asChild biến một link thành mục, cho hành động sang trang khác.

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

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="secondary">Tài khoản</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem asChild>
      <a href="#profile">Hồ sơ</a>
    </DropdownMenuItem>
    <DropdownMenuItem asChild>
      <a href="#billing">Thanh toán</a>
    </DropdownMenuItem>
    <DropdownMenuItem disabled>Cài đặt nhóm</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Nên và không nên

Nên

  • Mở đầu mỗi mục bằng một động từ: Đổi tên, Nhân bản, Xóa.
  • Đặt hành động destructive cuối cùng, sau một separator, và xác nhận chúng bằng AlertDialog.
  • Đặt tên trigger chỉ có icon bằng aria-label, chẳng hạn Hành động khác.

Không nên

  • Đừng dùng nó để chọn một giá trị trong form; dùng Select.
  • Đừng đặt field hoặc control khác vào nó; dùng Popover.
  • Đừng giấu cách duy nhất để làm một hành động thường gặp trong menu; cho nó một Button.

Props

TênKiểuGiá trịMặc địnhMô tả
openboolean--Đặt trên DropdownMenu. Nó có đang mở hay không, khi bạn kiểm soát nó. Ghép với onOpenChange.
defaultOpenboolean-falseĐặt trên DropdownMenu. Mở nó ở lần render đầu, khi bạn không kiểm soát nó.
onOpenChangefunction--Đặt trên DropdownMenu. Được gọi với true hoặc false khi nó mở hoặc đóng.
modalboolean-trueĐặt trên DropdownMenu. true giữ phần còn lại của trang ngoài tầm (không hover, không cuộn) khi menu đang mở.
sideenumtop | right | bottom | leftbottomĐặt trên DropdownMenuContent. Phía của trigger mà nó mở vào. Nó lật khi không đủ chỗ.
alignenumstart | center | endstartĐặt trên DropdownMenuContent. start căn menu với mép đầu của trigger; end cho trigger ở cuối một hàng.
sideOffsetnumber-4Đặt trên DropdownMenuContent. Khoảng cách giữa trigger và menu, tính bằng px. 4 là spacing-xs.
loopboolean-falseĐặt trên DropdownMenuContent. Các phím mũi tên quay từ mục cuối về mục đầu.
destructiveboolean-falseĐặt trên DropdownMenuItem. Chữ danger cho hành động xóa hoặc không hoàn tác được. Xác nhận bằng AlertDialog.
disabledboolean-falseĐặt trên một mục. Nó không được tô sáng hoặc chạy, và các phím mũi tên bỏ qua nó.
insetboolean-falseĐặt trên DropdownMenuItem hoặc DropdownMenuLabel. Căn label thẳng với các mục có icon hoặc dấu check.
leadingIconnode--Đặt trên DropdownMenuItem. Icon trang trí 16px trước label: <IconPencil size={16} />.
shortcutstring--Đặt trên DropdownMenuItem. Shortcut bàn phím ở cuối: ⌘D. Ứng dụng tự xử lý phím.
asChildboolean-falseĐặt trên DropdownMenuItem. Render phần tử con (một link) thành mục, cho hành động sang trang khác. leadingIcon và shortcut không áp dụng; đặt icon bên trong link.

Slot

TênBắt buộcMô tả
triggercóDropdownMenuTrigger với asChild bọc một Button.
contentcóDropdownMenuContent với một DropdownMenuItem cho mỗi hành động, theo thứ tự người dùng cần, các mục destructive để cuối. Nhóm menu dài bằng DropdownMenuLabel và DropdownMenuSeparator.

Cấu tạo

PhầnMô tả
rootDropdownMenuItem: một hành động. Chiều cao control md (32px với chuột, 36px với cảm ứng), góc trong, chữ primary 14px, icon đầu bằng màu icon primary, overlay hover trung tính khi được tô sáng. destructive đổi chữ và icon sang màu chữ danger.
destructiveMột DropdownMenuItem destructive (destructive): chữ danger trên cùng hàng trung tính và cùng kiểu tô sáng. Các class nằm trên mục.
destructiveIconIcon đầu của mục destructive, bằng màu chữ danger (không có token icon danger).
menuDropdownMenu. Giữ trạng thái mở; bản thân không render gì.
triggerDropdownMenuTrigger: button mở menu, thường là một Button với asChild.
contentDropdownMenuContent: danh sách nổi trên bề mặt raised, rộng ít nhất 192px, cùng bề mặt như danh sách của Select. Nó cuộn khi cao hơn màn hình trừ spacing-sm ở trên và dưới.
iconIcon đầu của một mục (leadingIcon), icon Tabler, 16px.
indicatorDấu check của DropdownMenuCheckboxItem (Tabler check, 16px) hoặc chấm 6px của DropdownMenuRadioItem, trước label.
groupLabelDropdownMenuLabel: tiêu đề của một nhóm, nhỏ hơn mục một bậc, bằng chữ phụ.
separatorDropdownMenuSeparator: một đường xuyên suốt menu, giữa hai nhóm.
shortcutDropdownMenuShortcut: một Kbd nhỏ gọn ở cuối hàng, với kiểu chữ UI. Nó là gợi ý; ứng dụng xử lý các phím.

Khả năng truy cập

Role: menu

PhímHành động
Space, Enter, ArrowDownTrên trigger: mở menu và focus vào mục đầu.
ArrowUp, ArrowDownDi chuyển giữa các mục, bỏ qua mục disabled. Khi có loop, nó quay từ mục cuối về mục đầu.
Home, EndFocus vào mục đầu hoặc mục cuối.
Enter, SpaceChạy mục và đóng menu. Trên mục checkbox hoặc radio, bật nó hoặc chọn nó.
EscapeĐóng menu và trả focus về trigger.
A letterFocus vào mục kế tiếp có label bắt đầu bằng chữ đó.
  • Trigger nhận aria-haspopup và aria-expanded; danh sách là một menu gồm menuitem, menuitemcheckbox và menuitemradio.
  • Đặt tên trigger chỉ có icon bằng aria-label: Hành động khác.
  • Mục destructive nói thứ nó xóa (Xóa dự án) và mở một AlertDialog; chữ danger không phải cảnh báo duy nhất.
  • Chữ shortcut được đọc cùng label. Ứng dụng tự xử lý shortcut; menu chỉ hiện nó.
  • Tiêu đề nhóm (DropdownMenuLabel) không focus được.

Cài đặt

npx werewolf-ui add dropdown-menu

Chạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.