ButtonGroup 按钮组

把一组按钮拼接为一个整体,共用边框与圆角。

import { AlignCenter, AlignLeft, AlignRight } from 'lucide-react'
import { ButtonGroup, IconButton } from '@hina-ui/react'

export default function Demo() {
  return (
    <ButtonGroup label="对齐方式">
      <IconButton label="左对齐" variant="outline">
        <AlignLeft />
      </IconButton>
      <IconButton label="居中" variant="outline">
        <AlignCenter />
      </IconButton>
      <IconButton label="右对齐" variant="outline">
        <AlignRight />
      </IconButton>
    </ButtonGroup>
  )
}
tsx

用法

import { ButtonGroup } from '@hina-ui/react'
ts

将按钮直接放入组容器即可,拼接由容器负责:首尾保留外侧的圆角,相接的一侧不保留圆角,相邻的边框重叠为一条,而不是并排的两条。

import { Button, ButtonGroup } from '@hina-ui/react'

export default function Demo() {
  return (
    <ButtonGroup label="视图">
      <Button variant="outline" tone="neutral">
        列表
      </Button>
      <Button variant="outline" tone="neutral">
        网格
      </Button>
      <Button variant="outline" tone="neutral">
        时间线
      </Button>
    </ButtonGroup>
  )
}
tsx

组内的按钮应当使用同一种变体与色调。只有地位相同的操作才适合拼在一起,主次不同的操作应当分开放置。

示例

变体

变体与色调由组内的每个按钮各自设置,组容器不会代为指定。

import { Button, ButtonGroup, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack align="center">
      <ButtonGroup label="填充">
        <Button variant="solid" tone="accent">
          上一步
        </Button>
        <Button variant="solid" tone="accent">
          保存
        </Button>
        <Button variant="solid" tone="accent">
          下一步
        </Button>
      </ButtonGroup>

      <ButtonGroup label="浅色">
        <Button variant="soft" tone="accent">
          上一步
        </Button>
        <Button variant="soft" tone="accent">
          保存
        </Button>
        <Button variant="soft" tone="accent">
          下一步
        </Button>
      </ButtonGroup>

      <ButtonGroup label="描边">
        <Button variant="outline" tone="neutral">
          上一步
        </Button>
        <Button variant="outline" tone="neutral">
          保存
        </Button>
        <Button variant="outline" tone="neutral">
          下一步
        </Button>
      </ButtonGroup>
    </Stack>
  )
}
tsx

尺寸

尺寸同样设置在按钮上。同一组内必须使用相同的尺寸,否则相邻按钮的高度无法对齐。

import { Button, ButtonGroup, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack align="center">
      <ButtonGroup label="小号">
        <Button size="sm" variant="outline" tone="neutral">
          日
        </Button>
        <Button size="sm" variant="outline" tone="neutral">
          周
        </Button>
        <Button size="sm" variant="outline" tone="neutral">
          月
        </Button>
      </ButtonGroup>

      <ButtonGroup label="中号">
        <Button variant="outline" tone="neutral">
          日
        </Button>
        <Button variant="outline" tone="neutral">
          周
        </Button>
        <Button variant="outline" tone="neutral">
          月
        </Button>
      </ButtonGroup>

      <ButtonGroup label="大号">
        <Button size="lg" variant="outline" tone="neutral">
          日
        </Button>
        <Button size="lg" variant="outline" tone="neutral">
          周
        </Button>
        <Button size="lg" variant="outline" tone="neutral">
          月
        </Button>
      </ButtonGroup>
    </Stack>
  )
}
tsx

纵向排列

设置 orientation="vertical" 之后,整组改为纵向拼接,相接的一侧随之转到上下两端,整组的宽度由最宽的一项决定。

import { Copy, Scissors, Trash2 } from 'lucide-react'
import { Button, ButtonGroup } from '@hina-ui/react'

export default function Demo() {
  return (
    <ButtonGroup label="文件操作" orientation="vertical" divider>
      <Button variant="soft" tone="neutral" icon={<Copy />}>
        复制
      </Button>
      <Button variant="soft" tone="neutral" icon={<Scissors />}>
        剪切
      </Button>
      <Button variant="soft" tone="neutral" icon={<Trash2 />}>
        删除
      </Button>
    </ButtonGroup>
  )
}
tsx

占满宽度

设置 block 之后整组占满容器的宽度,组内的按钮平分剩余空间。这一形态适用于对话框的底部与移动端界面。

import { Button, ButtonGroup } from '@hina-ui/react'

export default function Demo() {
  return (
    <ButtonGroup label="投票" block>
      <Button variant="outline" tone="neutral">
        赞成
      </Button>
      <Button variant="outline" tone="neutral">
        弃权
      </Button>
      <Button variant="outline" tone="neutral">
        反对
      </Button>
    </ButtonGroup>
  )
}
tsx

分隔线

底色相同的按钮拼在一起时,相邻的边界并不明显。设置 divider 会在按钮之间加一条细线,长度不占满整条边,颜色取自当前的文字颜色。

import { Button, ButtonGroup, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack align="center">
      <ButtonGroup label="不带分隔线">
        <Button variant="soft" tone="neutral">
          复制
        </Button>
        <Button variant="soft" tone="neutral">
          剪切
        </Button>
        <Button variant="soft" tone="neutral">
          粘贴
        </Button>
      </ButtonGroup>

      <ButtonGroup label="带分隔线" divider>
        <Button variant="soft" tone="neutral">
          复制
        </Button>
        <Button variant="soft" tone="neutral">
          剪切
        </Button>
        <Button variant="soft" tone="neutral">
          粘贴
        </Button>
      </ButtonGroup>
    </Stack>
  )
}
tsx

混排图标按钮

Button 与 IconButton 可以拼接在同一组中,常见的做法是在主操作之后加入一个下拉触发器。

import { ChevronDown } from 'lucide-react'
import { Button, ButtonGroup, IconButton } from '@hina-ui/react'

export default function Demo() {
  return (
    <ButtonGroup label="发布">
      <Button>立即发布</Button>
      <IconButton label="更多发布选项" variant="solid" tone="accent">
        <ChevronDown />
      </IconButton>
    </ButtonGroup>
  )
}
tsx

不可用

组容器没有 disabled 属性。需要禁用整组时,逐个设置按钮的 disabled;也可以只禁用其中的一个。

import { Button, ButtonGroup, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack align="center">
      <ButtonGroup label="整组不可用">
        <Button variant="outline" tone="neutral" disabled>
          加粗
        </Button>
        <Button variant="outline" tone="neutral" disabled>
          斜体
        </Button>
        <Button variant="outline" tone="neutral" disabled>
          下划线
        </Button>
      </ButtonGroup>

      <ButtonGroup label="单个不可用">
        <Button variant="outline" tone="neutral" disabled>
          上一页
        </Button>
        <Button variant="outline" tone="neutral">
          刷新
        </Button>
        <Button variant="outline" tone="neutral">
          下一页
        </Button>
      </ButtonGroup>
    </Stack>
  )
}
tsx

自定义样式

className 会追加到组容器上。需要改写首尾的圆角时,在容器上使用子元素选择器统一设置,不要逐个写在按钮上。

import { Button, ButtonGroup } from '@hina-ui/react'

export default function Demo() {
  return (
    <ButtonGroup
      label="排序"
      className="[&>*:first-child]:rounded-s-full [&>*:last-child]:rounded-e-full"
    >
      <Button variant="soft" tone="neutral" className="px-6">
        最新
      </Button>
      <Button variant="soft" tone="neutral" className="px-6">
        最热
      </Button>
      <Button variant="soft" tone="neutral" className="px-6">
        评分
      </Button>
    </ButtonGroup>
  )
}
tsx

行为

  • 组内的按钮不再有按下时的缩放。
  • 获得键盘焦点的按钮会提到上层,焦点框不被相邻按钮遮挡。
  • 组容器为 role="group",label 会作为整组的 aria-label。纵向排列时还会带上 aria-orientation="vertical"。

API

Props

属性
类型
默认值
说明
label
string
—
整组的无障碍名称
orientation
'horizontal' | 'vertical'
'horizontal'
拼接方向
block
boolean
false
是否占满容器宽度并平分空间
divider
boolean
false
是否在相邻按钮之间显示分隔线
className
string
—
追加至根元素的类名

内容属性

属性
说明
children
组内的按钮