DropdownMenu
点击触发的下拉菜单,支持嵌套子菜单、复选框组和单选组
下拉菜单(DropdownMenu)通过点击触发元素弹出,提供操作列表。组件基于 Radix DropdownMenu 封装,通过 items 数组数据驱动渲染,支持普通选项、子菜单、标签、分隔线、复选框组和单选组。
import {
DropdownMenu,
DropdownMenuCheckbox,
DropdownMenuRadio
} from '@skyroc/web-ui';架构说明
DropdownMenu 提供三个主入口组件,适应不同场景:
DropdownMenu:通用下拉菜单,items支持混合使用普通选项、子菜单、复选框组和单选组。DropdownMenuCheckbox:专用复选框菜单,当菜单仅包含复选项时使用,API 更简洁。DropdownMenuRadio:专用单选菜单,当菜单仅包含单选项时使用。
三者均为数据驱动:传入 items 数组,组件自动渲染对应的菜单结构。
内部子组件基于共享的 menu/ 基础层,注入 Radix DropdownMenu 原语(Item、CheckboxItem、RadioItem、Sub 等),确保样式和交互与其他菜单类组件(如 ContextMenu)保持一致。
何时使用
- 需要通过按钮点击展开操作列表时(如工具栏、更多操作)。
- 操作项较多且需要分组、嵌套时。
- 需要在菜单中提供状态切换(复选、单选)。
- 与 ContextMenu 的区分:DropdownMenu 由按钮点击触发,ContextMenu 由右键触发。
基础用法
children 作为触发元素,点击后弹出菜单。items 支持普通选项、标签、分隔线和嵌套子菜单,通过 type 字段区分。
<DropdownMenu
items={[
{ label: '编辑', leading: <Pencil className="size-4" /> },
{ label: '复制', shortcut: '⌘C' },
{ type: 'separator' },
{
type: 'sub',
label: '更多',
children: [
{ label: '设置' },
{ label: '偏好' }
]
}
]}
>
<button>操作</button>
</DropdownMenu>箭头
通过 contentProps.showArrow 显示指向触发元素的箭头。箭头样式可通过 classNames.arrow 或内容属性中的箭头 class 配置覆盖。
<DropdownMenu
contentProps={{ showArrow: true }}
items={items}
>
<Button>操作</Button>
</DropdownMenu>复选框组
通过 type: 'checkbox' 在菜单中嵌入复选框组,checks 和 onChecksChange 控制勾选状态。也可直接使用 DropdownMenuCheckbox 便捷组件。
<DropdownMenuCheckbox
items={[
{ label: '加粗', value: 'bold' },
{ label: '斜体', value: 'italic' },
{ type: 'separator' },
{ label: '删除线', value: 'strikethrough' }
]}
checks={checks}
onChecksChange={setChecks}
>
<button>文本格式</button>
</DropdownMenuCheckbox>单选组
通过 type: 'radio' 在菜单中嵌入单选组,value 和 onValueChange 控制选中状态。也可直接使用 DropdownMenuRadio 便捷组件。
<DropdownMenuRadio
items={[
{ label: '小', value: 'sm' },
{ label: '中', value: 'md' },
{ label: '大', value: 'lg' }
]}
value={size}
onValueChange={setSize}
>
<button>字号</button>
</DropdownMenuRadio>混合模式
普通选项、子菜单、复选框组和单选组可以在同一个 items 数组中混合使用。
<DropdownMenu
items={[
{ label: '新建文件' },
{ label: '打开文件', shortcut: '⌘O' },
{ type: 'separator' },
{
type: 'checkbox',
checks: viewOptions,
onChecksChange: setViewOptions,
children: [
{ type: 'label', label: '视图选项' },
{ label: '显示行号', value: 'lineNumbers' },
{ label: '自动换行', value: 'wordWrap' }
]
},
{ type: 'separator' },
{
type: 'radio',
value: theme,
onValueChange: setTheme,
children: [
{ type: 'label', label: '主题' },
{ label: '浅色', value: 'light' },
{ label: '深色', value: 'dark' },
{ label: '跟随系统', value: 'system' }
]
}
]}
>
<button>菜单</button>
</DropdownMenu>API
DropdownMenu
通用属性参考:支持 Radix DropdownMenu Root 的 dir、modal、open、defaultOpen、onOpenChange 属性。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| children | 触发元素,点击后弹出菜单 | ReactNode | - |
| items* | 菜单项数据数组,支持普通选项、子菜单、复选框组、单选组、标签和分隔线 | DropdownMenuOption[] | - |
| className | 菜单内容容器的 class | ClassValue | - |
| classNames | 各 slot 的自定义 class | MenuClassNames | - |
| size | 尺寸,影响所有菜单项的字号与间距 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'md' |
| contentProps | 传递给菜单内容容器的额外属性 | DropdownMenuContentProps | - |
| open | 受控模式下的打开状态 | boolean | - |
| defaultOpen | 非受控模式下的初始打开状态 | boolean | - |
| onOpenChange | 菜单打开/关闭状态变化回调 | (open: boolean) => void | - |
| dir | 文本方向 | 'ltr' | 'rtl' | - |
| modal | 是否以模态模式打开 | boolean | - |
选项数据结构
items 数组中的每个元素通过 type 字段区分类型:
| 类型 | 说明 | 必填字段 |
|---|---|---|
item | 可选择的菜单项(默认类型,可省略) | label |
label | 不可交互的分组标签 | type、label |
separator | 分隔线 | type |
sub | 子菜单,展开后显示嵌套选项 | type、children |
checkbox | 复选框组,支持多选 | type、children |
radio | 单选组,支持互斥选择 | type、children |
普通选项(item)
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| label | 选项显示文本 | ReactNode | - |
| type | 标识为普通选项,可省略 | 'item' | - |
| onSelect | 选中时触发的回调 | (event: Event) => void | - |
| disabled | 是否禁用 | boolean | - |
| leading | 前置插槽,通常放图标 | ReactNode | - |
| trailing | 后置插槽 | ReactNode | - |
| shortcut | 关联的键盘快捷键 | string | string[] | - |
| className | 选项的 class | ClassValue | - |
| classNames | 选项内各 slot 的 class(item / shortcut) | Pick<MenuClassNames, 'item' | 'shortcut'> | - |
子菜单(sub)
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| type* | 标识为子菜单 | 'sub' | - |
| label | 子菜单触发项的显示文本 | ReactNode | - |
| children* | 子菜单内的选项数组,支持嵌套 | MenuOptionData[] | - |
| leading | 前置插槽 | ReactNode | - |
| trailing | 后置插槽 | ReactNode | - |
| triggerIcon | 子菜单展开指示图标 | ReactNode | - |
| className | 触发项的 class | ClassValue | - |
| classNames | 触发项图标 slot 的 class | Pick<MenuClassNames, 'subTriggerIcon'> | - |
复选框组(checkbox)
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| type* | 标识为复选框组 | 'checkbox' | - |
| children* | 复选项数组,每项包含 label 和 value | MenuCheckboxGroupItemProps[] | - |
| checks | 当前已勾选的值数组 | string[] | - |
| onChecksChange | 勾选状态变化回调 | (checks: string[]) => void | - |
单选组(radio)
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| type* | 标识为单选组 | 'radio' | - |
| children* | 单选项数组,每项包含 label 和 value | MenuRadioItemOptionProps[] | - |
| value | 当前选中的值 | string | - |
| onValueChange | 选中值变化回调 | (value: string) => void | - |
DropdownMenuCheckbox
纯复选框菜单的便捷组件。当菜单仅包含复选项时,可直接使用此组件代替 DropdownMenu。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| children | 触发元素,点击后弹出菜单 | ReactNode | - |
| items* | 复选项数组 | MenuCheckboxGroupItemProps[] | - |
| checks | 当前已勾选的值数组 | string[] | - |
| onChecksChange | 勾选状态变化回调 | (checks: string[]) => void | - |
| classNames | 各 slot 的自定义 class | MenuClassNames | - |
| size | 尺寸 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'md' |
| contentProps | 传递给菜单内容容器的额外属性 | DropdownMenuContentProps | - |
| open | 受控模式下的打开状态 | boolean | - |
| defaultOpen | 非受控模式下的初始打开状态 | boolean | - |
| onOpenChange | 菜单打开/关闭状态变化回调 | (open: boolean) => void | - |
DropdownMenuRadio
纯单选菜单的便捷组件。当菜单仅包含单选项时,可直接使用此组件代替 DropdownMenu。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| children | 触发元素,点击后弹出菜单 | ReactNode | - |
| items* | 单选项数组 | MenuRadioItemOptionProps[] | - |
| value | 当前选中的值 | string | - |
| onValueChange | 选中值变化回调 | (value: string) => void | - |
| classNames | 各 slot 的自定义 class | MenuClassNames | - |
| size | 尺寸 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'md' |
| contentProps | 传递给菜单内容容器的额外属性 | DropdownMenuContentProps | - |
| open | 受控模式下的打开状态 | boolean | - |
| defaultOpen | 非受控模式下的初始打开状态 | boolean | - |
| onOpenChange | 菜单打开/关闭状态变化回调 | (open: boolean) => void | - |
类型
DropdownMenuContentProps
菜单内容容器属性。继承 Radix DropdownMenu Content 的定位属性(side、sideOffset、align、alignOffset 等)。
| 字段 | 类型 | 说明 |
|---|---|---|
| className | ClassValue | 内容容器 class。 |
| size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 尺寸。 |
| showArrow | boolean | 是否显示箭头。 |
| arrowClass | ClassValue | 箭头 class。 |
| side | 'top' | 'right' | 'bottom' | 'left' | 弹出方向。 |
| sideOffset | number | 弹出方向偏移量(px)。 |
| align | 'start' | 'center' | 'end' | 对齐方式。 |
| alignOffset | number | 对齐方向偏移量(px)。 |
MenuOptionData
普通菜单选项数据联合类型,用于 items 和子菜单 children。通过 type 字段区分:'item'(可省略)为普通选项,'label' 为标签,'separator' 为分隔线,'sub' 为子菜单。详见上方「选项数据结构」。
DropdownMenuOption
DropdownMenu items 数组的元素类型。普通菜单项通过 MenuOptionData 表达(含 item / label / separator / sub 四种),复选和单选通过专用选项类型表达。
DropdownMenuCheckboxOption
复选框组选项,嵌入在 DropdownMenu items 中使用
DropdownMenuRadioOption
单选组选项,嵌入在 DropdownMenu items 中使用