跳到主要内容

DropdownMenu

  • 组件说明: 下拉菜单组件,用于在触发元素下方展示一组操作项,支持 Default/Danger 语义变体、图标插槽和级联子菜单。
  • 尺寸基线: Content min-width 160px, padding-y 8px, radius 5px; Item padding 16px × 8px, font 14px/20px。
  • 实现约定: 标准用法通过 items 声明式配置,级联子菜单也通过 subItems 描述;仅在 CheckboxItem / RadioItem 等高级场景下再使用组合式 API。ui/dropdown-menu 保留结构骨架和动画,design 层通过 unstyledVisual 接管视觉。
  • Figma 规范

基础用法

通过 items 声明式配置菜单项,children 放触发元素。

结果
Loading...
实时编辑器
render(
  <DropdownMenu
    items={[{ label: '个人资料' }, { label: '账户设置' }, { type: 'separator' }, { label: '退出登录' }]}
  >
    <Button variant="secondary">打开菜单</Button>
  </DropdownMenu>,
)

变体

通过 variant 区分操作语义。

结果
Loading...
实时编辑器
render(
  <DropdownMenu
    items={[
      { label: '编辑' },
      { label: '复制' },
      { type: 'separator' },
      { label: '删除', variant: 'danger' },
    ]}
  >
    <Button variant="secondary">操作</Button>
  </DropdownMenu>,
)

状态

结果
Loading...
实时编辑器
render(
  <DropdownMenu
    items={[
      { label: '正常项' },
      { label: '禁用项', disabled: true },
      { type: 'separator' },
      { label: '危险项', variant: 'danger' },
      { label: '禁用危险项', variant: 'danger', disabled: true },
    ]}
  >
    <Button variant="secondary">状态展示</Button>
  </DropdownMenu>,
)

带图标

通过 icon 为菜单项添加前置图标。

结果
Loading...
实时编辑器
const EditIcon = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M10.5 1.75L12.25 3.5L10.5 5.25M1.75 12.25H3.5L10.5 5.25L8.75 3.5L1.75 10.5V12.25Z" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"/>
  </svg>
)

const TrashIcon = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M1.75 3.5H12.25M5.25 6.125V10.375M8.75 6.125V10.375M2.625 3.5L3.5 11.375C3.5 11.8582 3.89175 12.25 4.375 12.25H9.625C10.1082 12.25 10.5 11.8582 10.5 11.375L11.375 3.5M4.375 3.5V2.625C4.375 2.14175 4.76675 1.75 5.25 1.75H8.75C9.23325 1.75 9.625 2.14175 9.625 2.625V3.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"/>
  </svg>
)

const ArrowIcon = ({ direction }) => {
  const rotationMap = {
    up: 'rotate(-180deg)',
    right: 'rotate(-90deg)',
    down: 'rotate(0deg)',
    left: 'rotate(90deg)',
  }

  return (
    <svg
      width="14"
      height="14"
      viewBox="0 0 14 14"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      style={{ transform: rotationMap[direction] }}
    >
      <path
        d="M3.5 5.25L7 8.75L10.5 5.25"
        stroke="currentColor"
        strokeWidth="1.2"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  )
}

render(
  <DropdownMenu
    items={[
      { label: '编辑', icon: <EditIcon /> },
      { label: '向上箭头', icon: <ArrowIcon direction="up" /> },
      { label: '向右箭头', icon: <ArrowIcon direction="right" /> },
      { label: '向下箭头', icon: <ArrowIcon direction="down" /> },
      { label: '向左箭头', icon: <ArrowIcon direction="left" /> },
      { type: 'separator' },
      { label: '删除', variant: 'danger', icon: <TrashIcon /> },
    ]}
  >
    <Button variant="secondary">带图标</Button>
  </DropdownMenu>,
)

带标签分组

结果
Loading...
实时编辑器
render(
  <DropdownMenu
    items={[
      { type: 'label', label: '我的账户' },
      { label: '个人资料' },
      { label: '账户设置' },
      { type: 'separator' },
      { type: 'label', label: '团队' },
      { label: '团队设置' },
      { label: '邀请成员' },
    ]}
  >
    <Button variant="secondary">分组菜单</Button>
  </DropdownMenu>,
)

级联子菜单

结果
Loading...
实时编辑器
render(
  <DropdownMenu
    items={[
      { label: '新建文件' },
      {
        label: '更多选项',
        subItems: [{ label: '导入' }, { label: '导出' }],
      },
      { type: 'separator' },
      { label: '删除', variant: 'danger' },
    ]}
  >
    <Button variant="secondary">级联菜单</Button>
  </DropdownMenu>,
)

尺寸规范

Content 容器

属性Token
最小宽度160px
纵向内边距Spacing_88px
圆角Radius_55px
阴影Effects/Shadow/Default0 0 32px rgba(0,0,0,0.1)

Item 项

属性Token
水平内边距Spacing_1616px
纵向内边距Spacing_88px
字号Font-Size/Body14px
行高Line-Height/Body22px
图标容器20×20px

颜色 Token

状态文本色Hover 背景
DefaultLabels/Secondary#3d3d3dGrays/Gray-1#ebebeb
DangerLabels/Error#cc3325Grays/Gray-1#ebebeb
DisabledLabels/Disabled#a3a3a3

Props

属性类型默认值说明
childrenReactNode-触发元素
itemsDropdownMenuItemEntry[]-声明式菜单项配置
asChildbooleantrue是否将 children 作为 Trigger 本体
openboolean-受控模式开关
onOpenChange(open: boolean) => void-开关变化回调
contentClassNamestring-Content 自定义类名
side'top' | 'right' | 'bottom' | 'left''bottom'弹出方向
align'start' | 'center' | 'end''start'对齐方式
类型type 值必填属性说明
菜单项'item'(可省略)label支持 varianticondisabledonSelectsubItemsitemProps
分隔线'separator'-渲染为 DropdownMenuSeparator
分组标题'label'label渲染为 DropdownMenuLabel
属性类型默认值说明
childrenReactNode-菜单项内容
variant'default' | 'danger''default'语义变体
iconReactNode-前置图标
disabledbooleanfalse禁用状态
onSelect(event: Event) => void-选中回调
classNamestring-自定义类名

高级用法

默认优先使用 items / subItems。只有在需要 CheckboxItem、RadioItem 或完全自定义内容组合时,再切换到 DropdownMenu + DropdownMenuTrigger + DropdownMenuContent