Dropdown 下拉菜单
下拉菜单展示一组可供用户选择的操作或选项。
引入
import { Dropdown } from '@heroui/react';用法
"use client";
import {Button, Dropdown, Label} from "@heroui/react";
export function Default() {组件结构
引入 Dropdown 组件并通过点语法访问所有子部分。
import { Dropdown, Button, Label, Description, Header, Kbd, Separator } from '@heroui/react';
export default () => (
<Dropdown>
<Dropdown.Trigger>
<Button />
</Dropdown.Trigger>
<Dropdown.Popover>
<Dropdown.Menu>
<Dropdown.Item>
<Label />
<Description />
<Kbd slot="keyboard" />
<Dropdown.ItemIndicator />
</Dropdown.Item>
<Separator />
<Dropdown.Section>
<Header />
<Dropdown.Item />
</Dropdown.Section>
<Dropdown.SubmenuTrigger>
<Dropdown.Item>
<Label />
<Dropdown.SubmenuIndicator />
</Dropdown.Item>
<Dropdown.Popover>
<Dropdown.Menu>
<Dropdown.Item />
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown.SubmenuTrigger>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>
)带单选
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Label} from "@heroui/react";单选且自定义指示器
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Label} from "@heroui/react";带多选
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Label} from "@heroui/react";带分组级选择
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Kbd, Label, Separator} from "@heroui/react";带键盘快捷键
"use client";
import {Button, Dropdown, Kbd, Label} from "@heroui/react";
export function WithKeyboardShortcuts() {带图标
"use client";
import {FloppyDisk, FolderOpen, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Dropdown, Kbd, Label} from "@heroui/react";
长按触发
import {Button, Dropdown, Label} from "@heroui/react";
export function LongPressTrigger() {
return (
<Dropdown trigger="longPress">带描述
"use client";
import {FloppyDisk, FolderOpen, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Description, Dropdown, Kbd, Label} from "@heroui/react";
带分组
"use client";
import {EllipsisVertical, Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Description, Dropdown, Header, Kbd, Label, Separator} from "@heroui/react";
带禁用项
"use client";
import {Bars, Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Description, Dropdown, Header, Kbd, Label, Separator} from "@heroui/react";
带子菜单
"use client";
import {Button, Dropdown, Label} from "@heroui/react";
export function WithSubmenus() {带自定义子菜单指示器
"use client";
import {ArrowRight} from "@gravity-ui/icons";
import {Button, Dropdown, Label} from "@heroui/react";
受控
已选:bold
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Label} from "@heroui/react";受控展开状态
下拉菜单:关闭
"use client";
import {Button, Dropdown, Label} from "@heroui/react";
import {useState} from "react";
自定义触发器
import {ArrowRightFromSquare, Gear, Persons} from "@gravity-ui/icons";
import {Avatar, Dropdown, Label} from "@heroui/react";
export function CustomTrigger() {
return (样式
传入 Tailwind CSS 类
import { Dropdown, Button } from '@heroui/react';
function CustomDropdown() {
return (
<Dropdown>
<Dropdown.Trigger className="rounded-lg border p-2 bg-surface">
<Button>Actions</Button>
</Dropdown.Trigger>
<Dropdown.Popover className="min-w-[200px]">
<Dropdown.Menu>
<Dropdown.Item id="item-1" textValue="Item 1" className="hover:bg-surface-secondary">
Item 1
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>
);
}自定义组件类
若要自定义 Dropdown 组件类,可使用 @layer components 指令。
了解更多。
@layer components {
.dropdown {
@apply flex flex-col gap-1;
}
.dropdown__trigger {
@apply outline-none;
}
.dropdown__popover {
@apply rounded-lg border border-border bg-overlay p-2;
}
.dropdown__menu {
@apply flex flex-col gap-1;
}
}HeroUI 遵循 BEM 方法论,确保组件变体和状态可复用且易于自定义。
CSS 类
Dropdown 组件使用以下 CSS 类(查看源码样式):
基础类
.dropdown- Dropdown 根容器.dropdown__trigger- 用于触发 Dropdown 的按钮或元素.dropdown__popover- Popover 容器.dropdown__menu- Popover 内的菜单容器
状态类
.dropdown__trigger[data-focus-visible="true"]- 触发器聚焦状态.dropdown__trigger[data-disabled="true"]- 触发器禁用状态.dropdown__trigger[data-pressed="true"]- 触发器按下状态.dropdown__popover[data-entering]- 进入动画状态.dropdown__popover[data-exiting]- 退出动画状态.dropdown__menu[data-selection-mode="single"]- 单选模式.dropdown__menu[data-selection-mode="multiple"]- 多选模式
菜单组件类
Dropdown 使用 Menu、MenuItem 与 MenuSection 作为底层组件。以下类名也可用于自定义:
Menu 类
.menu- 菜单容器(menu.css)[data-slot="separator"]- 菜单内的分隔线元素
MenuItem 类
.menu-item- 菜单项容器(menu-item.css).menu-item__indicator- 选中指示器(对勾或圆点)[data-slot="menu-item-indicator--checkmark"]- 对勾指示器 SVG[data-slot="menu-item-indicator--dot"]- 圆点指示器 SVG
.menu-item__indicator--submenu- 子菜单指示器(箭头).menu-item--default- 默认样式变体.menu-item--danger- 危险样式变体
MenuItem 状态类
.menu-item[data-focus-visible="true"]- 聚焦状态(键盘焦点).menu-item[data-focus="true"]- 聚焦状态.menu-item[data-pressed]- 按下状态.menu-item[data-hovered]- 悬停状态.menu-item[data-selected="true"]- 选中状态.menu-item[data-disabled]- 禁用状态.menu-item[data-has-submenu="true"]- 带子菜单的项.menu-item[data-selection-mode="single"]- 单选模式.menu-item[data-selection-mode="multiple"]- 多选模式.menu-item[aria-checked="true"]- 已勾选(ARIA).menu-item[aria-selected="true"]- 已选中(ARIA)
MenuSection 类
.menu-section- 菜单分区容器(menu-section.css)
交互状态
该组件同时支持 CSS 伪类和 data 属性,便于灵活组合:
- 悬停:触发器与菜单项上
:hover或[data-hovered="true"] - 聚焦:触发器与菜单项上
:focus-visible或[data-focus-visible="true"] - 禁用:触发器与菜单项上
:disabled或[data-disabled="true"] - 按下:触发器与菜单项上
:active或[data-pressed="true"] - 选中:菜单项上
[data-selected="true"]或[aria-selected="true"]
API 参考
Dropdown Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
isOpen | boolean | - | 设置菜单展开状态(受控)。 |
defaultOpen | boolean | - | 设置菜单默认展开状态(非受控)。 |
onOpenChange | (isOpen: boolean) => void | - | 展开状态变化时调用的事件处理函数。 |
trigger | "press" | "longPress" | "press" | 触发菜单的交互类型。 |
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | - | Dropdown 内容。 |
Dropdown.Trigger Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | RenderFunction | - | 触发器内容或渲染函数。 |
使用 Button 作为触发器时,同样支持所有 Button props。
Dropdown.Popover Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
placement | "bottom" | "bottom left" | "bottom right" | "bottom start" | "bottom end" | "top" | "top left" | "top right" | "top start" | "top end" | "left" | "left top" | "left bottom" | "start" | "start top" | "start bottom" | "right" | "right top" | "right bottom" | "end" | "end top" | "end bottom" | "bottom" | 相对于触发器的 Popover 位置。 |
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | - | 子内容。 |
同样支持所有 Popover props。
Dropdown.Menu Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
selectionMode | "single" | "multiple" | "none" | "none" | 是否启用单选、多选或不启用选择。 |
selectedKeys | Iterable<Key> | - | 当前选中的 key(受控)。 |
defaultSelectedKeys | Iterable<Key> | - | 初始选中的 key(非受控)。 |
onSelectionChange | (keys: Selection) => void | - | 选中变化时调用的事件处理函数。 |
disabledKeys | Iterable<Key> | - | 禁用项的 key。 |
onAction | (key: Key) => void | - | 激活菜单项时调用的事件处理函数。 |
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | - | 菜单内容。 |
同样支持所有 Menu props。
Dropdown.Section Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
selectionMode | "single" | "multiple" | - | 该分组内菜单项的选择模式。 |
selectedKeys | Iterable<Key> | - | 当前选中的 key(受控)。 |
defaultSelectedKeys | Iterable<Key> | - | 初始选中的 key(非受控)。 |
onSelectionChange | (keys: Selection) => void | - | 选中变化时调用的事件处理函数。 |
disabledKeys | Iterable<Key> | - | 禁用项的 key。 |
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | - | 分组内容。 |
同样支持所有 MenuSection props。
Dropdown.Item Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
id | Key | - | 菜单项唯一标识。 |
textValue | string | - | 用于首字母导航的文本内容。 |
variant | "default" | "danger" | "default" | 菜单项视觉变体。 |
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | RenderFunction | - | 菜单项内容或渲染函数。 |
同样支持所有 MenuItem props。
Dropdown.ItemIndicator Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
type | "checkmark" | "dot" | "checkmark" | 指示器类型。 |
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | RenderFunction | - | 自定义指示器内容或渲染函数。 |
使用渲染函数时,会传入以下值:
| Prop | 类型 | 描述 |
|---|---|---|
isSelected | boolean | 该项是否选中。 |
isIndeterminate | boolean | 该项是否处于不确定状态。 |
Dropdown.SubmenuIndicator Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | - | 自定义指示器内容。 |
Dropdown.SubmenuTrigger Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
className | string | - | 额外的 Tailwind CSS 类。 |
children | ReactNode | - | 子菜单触发器内容。 |
同样支持所有 SubmenuTrigger props。
RenderProps
在 Dropdown.Item 中使用渲染函数时,会传入以下值:
| Prop | 类型 | 描述 |
|---|---|---|
isSelected | boolean | 该项是否选中。 |
isFocused | boolean | 该项是否聚焦。 |
isDisabled | boolean | 该项是否禁用。 |
isPressed | boolean | 该项是否处于按下状态。 |
示例
基础用法
import { Dropdown, Button, Label } from '@heroui/react';
<Dropdown>
<Button aria-label="Menu" variant="secondary">
Actions
</Button>
<Dropdown.Popover>
<Dropdown.Menu onAction={(key) => alert(`Selected: ${key}`)}>
<Dropdown.Item id="new-file" textValue="New file">
<Label>New file</Label>
</Dropdown.Item>
<Dropdown.Item id="open-file" textValue="Open file">
<Label>Open file</Label>
</Dropdown.Item>
<Dropdown.Item id="delete-file" textValue="Delete file" variant="danger">
<Label>Delete file</Label>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>带分组
import { Dropdown, Button, Label, Header, Separator } from '@heroui/react';
<Dropdown>
<Button aria-label="Menu" variant="secondary">
Actions
</Button>
<Dropdown.Popover>
<Dropdown.Menu onAction={(key) => alert(`Selected: ${key}`)}>
<Dropdown.Section>
<Header>Actions</Header>
<Dropdown.Item id="new-file" textValue="New file">
<Label>New file</Label>
</Dropdown.Item>
<Dropdown.Item id="edit-file" textValue="Edit file">
<Label>Edit file</Label>
</Dropdown.Item>
</Dropdown.Section>
<Separator />
<Dropdown.Section>
<Header>Danger zone</Header>
<Dropdown.Item id="delete-file" textValue="Delete file" variant="danger">
<Label>Delete file</Label>
</Dropdown.Item>
</Dropdown.Section>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>受控选择
import type { Selection } from '@heroui/react';
import { Dropdown, Button, Label } from '@heroui/react';
import { useState } from 'react';
function ControlledDropdown() {
const [selected, setSelected] = useState<Selection>(new Set(['bold']));
return (
<Dropdown>
<Button aria-label="Menu" variant="secondary">
Actions
</Button>
<Dropdown.Popover>
<Dropdown.Menu
selectedKeys={selected}
selectionMode="multiple"
onSelectionChange={setSelected}
>
<Dropdown.Item id="bold" textValue="Bold">
<Label>Bold</Label>
<Dropdown.ItemIndicator />
</Dropdown.Item>
<Dropdown.Item id="italic" textValue="Italic">
<Label>Italic</Label>
<Dropdown.ItemIndicator />
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>
);
}带子菜单
import { Dropdown, Button, Label } from '@heroui/react';
<Dropdown>
<Button aria-label="Menu" variant="secondary">
Share
</Button>
<Dropdown.Popover>
<Dropdown.Menu onAction={(key) => alert(`Selected: ${key}`)}>
<Dropdown.Item id="copy-link" textValue="Copy Link">
<Label>Copy Link</Label>
</Dropdown.Item>
<Dropdown.SubmenuTrigger>
<Dropdown.Item id="share" textValue="Share">
<Label>Other</Label>
<Dropdown.SubmenuIndicator />
</Dropdown.Item>
<Dropdown.Popover>
<Dropdown.Menu>
<Dropdown.Item id="whatsapp" textValue="WhatsApp">
<Label>WhatsApp</Label>
</Dropdown.Item>
<Dropdown.Item id="telegram" textValue="Telegram">
<Label>Telegram</Label>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown.SubmenuTrigger>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>无障碍
Dropdown 组件实现 ARIA 菜单模式,并提供:
- 完整键盘导航(方向键、Home/End、首字母导航)
- 屏幕阅读器对操作与选中变化的播报
- 合理的焦点管理
- 禁用态支持
- 长按交互支持
- 子菜单导航
更多信息见 React Aria Menu 文档。





