Dropdown menu
Mẫu chuẩnMenu hành động, checklist cột, và radio cho một bộ lọc. Ô trong biểu mẫu vẫn là Select.
Playground
Menu được portal ra ngoài vùng brand, nên panel theo theme của trang, không theo brand đang chọn trong playground.
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@nexobox/ui";
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button>Hành động</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" side="bottom">
<DropdownMenuLabel>Hàng 128</DropdownMenuLabel>
<DropdownMenuGroup>
<DropdownMenuItem onSelect={() => {}}>Sửa</DropdownMenuItem>
<DropdownMenuItem onSelect={() => {}}>Nhân bản</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem onSelect={() => {}}>Xuất</DropdownMenuItem>
<DropdownMenuItem disabled>Xoá</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Khi nào sử dụng
Nên dùng
Một nhóm hành động neo vào một nút: sửa, nhân bản, xuất, xoá trên một hàng; menu tài khoản.
Tránh dùng
Chọn một giá trị để gửi kèm biểu mẫu — đó là Select, không phải dropdown menu. Nội dung tự do hay một form nhỏ thì dùng Popover. Không dùng làm điều hướng chính. Menu chuột phải và menu ứng dụng: chưa có.
Anatomy
Root giữ trạng thái mở/đóng. Trigger thường asChild bọc một Button. Content portal ra document.body, lớp --nf-foundation-layer-dropdown. Item là một hành động, Label là nhãn nhóm không tương tác, Separator chia hai nhóm, Group gom nhiều Item không tự render viền.
Variants
Không có variant, không có size. Các phần dưới đây chỉ hiển thị khi menu đang mở, vì DropdownMenuContent portal ra document.body — bảng này liệt kê từng phần ở trạng thái tĩnh thay vì mở một menu thật trong khung xem trước.
| Phần | Trạng thái | Ghi chú |
|---|---|---|
| Item | Mặc định | Nền trong suốt, chữ --nf-semantic-text-primary. Cao --nf-component-menu-item-height: 36 px comfortable, 32 px compact, 44 px con trỏ thô. |
| Item | Highlighted | Nền --nf-component-menu-item-hover khi được rê hoặc điều hướng bàn phím tới, qua data-[highlighted] |
| Item | Pressed | Nền --nf-component-menu-item-pressed, giữ chuột xuống. Không co scale — DS-018 rút press-scale khỏi mọi primitive. |
| Item | Focus-visible | Không có. data-[highlighted] là chỉ báo duy nhất — ring cộng nền highlighted đọc như hai con trỏ cùng lúc. Miễn trừ có tên trong A36, không phải khiếm khuyết. |
| Item | Disabled | Con trỏ not-allowed, chữ --nf-component-button-disabled-foreground |
| Label | Mặc định | Chữ --nf-semantic-text-muted, không tương tác |
| Separator | Mặc định | Đường kẻ --nf-semantic-border-subtle |
| Group | Hai mục | Không tự render viền hay khoảng cách riêng — chỉ để gom Item cho screen reader |
Checkbox giữ menu mở. Radio đóng menu. Không có submenu. Không có loading, error, empty.
Design tokens
Content đọc --nf-semantic-surface-raised, --nf-component-menu-radius, --nf-component-menu-padding, --nf-component-overlay-shadow, --nf-motion-menu-in. Item đọc --nf-component-menu-item-height, -item-hover, -item-pressed, -item-padding-inline, -item-gap, --nf-component-field-radius. Label đọc --nf-semantic-text-muted. Nhóm token --nf-component-menu-* giờ đã có — item rời thang hàng bảng cũ (48 px) và neo vào chiều cao riêng của menu; không có --nf-component-dropdown-* vì Content dùng chung nhóm menu với Select và Combobox.
API & triển khai
| Prop | Mặc định | Quy ước |
|---|---|---|
| open / onOpenChange | — | Trên Root. Chế độ controlled. |
| modal | true | Của Radix, trên Root. |
| asChild | false | Trên Trigger, thường bọc Button. |
| align / side / sideOffset | start / bottom / 8 | Trên Content. |
| disabled | false | Trên Item. Mục không chạy được. |
| onSelect | — | Trên Item. preventDefault() để giữ menu mở. |