Chuyển tới nội dung

Pro đang mở bán trước. Cài đặt mở từ tháng 1/2027. Xem Pro

Component

ButtonGroup

Một hàng hoặc cột Button liên quan có tên, nối thành một khối có cạnh chung hoặc cách nhau. Nhóm đặt một size và variant cho các Button của nó.

  • npm: 1 trực tiếp, 4 tổng
  • registry: 3 trực tiếp, 3 tổng

Xem trước

Props

  • orientation
  • attached
  • size
  • variant
  • fullWidth
  • content
import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>

Cách dùng

Khi nào dùng

  • Giữ hai đến năm thao tác liên quan cùng nhau, như Copy, Edit và Delete trong toolbar.
  • Một thao tác chính với menu thêm bên cạnh (split button).

Khi nào không dùng

  • Một lựa chọn luôn được chọn, như view hoặc căn chỉnh. Dùng ToggleGroup hoặc Tabs.
  • Các thao tác không liên quan, hoặc thao tác chính cạnh Cancel. Đặt các Button cạnh nhau.
  • Chuyển giữa các trang kết quả. Dùng Pagination.

Biến thể

orientation

Một hàng hoặc một cột Button.

  • horizontalmặc định

  • vertical

import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup orientation="vertical" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>

size

Size của mọi Button trong nhóm, cùng các bước với Button: sm 28px, md 32px, lg 36px (mặc định của nhóm), xl 44px với chuột; trên cảm ứng md là 36px, lg 44px và xl 48px. Button tự đặt size thì giữ size của nó.

  • sm

  • md

  • lgmặc định

  • xl

import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup size="sm" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup size="md" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup size="xl" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>

variant

Variant của mọi Button trong nhóm. Button tự đặt variant thì giữ variant của nó. Nhóm nối liền vẽ một shadow cho variant (shadow-low cho secondary và solid, shadow-med cho các bản glossy) thay vì mỗi Button một shadow. Đặt ButtonGroupSeparator giữa các Button solid nối liền.

  • secondarymặc định

  • solid

  • soft

  • ghost

  • destructive

  • destructive-soft

  • glossy

  • destructive-glossy

import { Button } from "@/components/ui/button"
import { ButtonGroup, ButtonGroupSeparator } from "@/components/ui/button-group"

<ButtonGroup aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup variant="solid" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <ButtonGroupSeparator />
  <Button>Sửa</Button>
  <ButtonGroupSeparator />
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup variant="soft" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup variant="ghost" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup variant="destructive" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <ButtonGroupSeparator />
  <Button>Sửa</Button>
  <ButtonGroupSeparator />
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup variant="destructive-soft" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <Button>Sửa</Button>
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup variant="glossy" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <ButtonGroupSeparator />
  <Button>Sửa</Button>
  <ButtonGroupSeparator />
  <Button>Xóa</Button>
</ButtonGroup>
<ButtonGroup variant="destructive-glossy" aria-label="Thao tác với tệp">
  <Button>Nhân bản</Button>
  <ButtonGroupSeparator />
  <Button>Sửa</Button>
  <ButtonGroupSeparator />
  <Button>Xóa</Button>
</ButtonGroup>

Ví dụ

Thao tác nối liền

import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup aria-label="Thao tác tệp">
  <Button>Đổi tên</Button>
  <Button>Nhân bản</Button>
  <Button>Archive</Button>
</ButtonGroup>

Icon và label

Button chỉ có icon mang tên riêng.

import { IconBold, IconItalic, IconUnderline } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup aria-label="Định dạng văn bản">
  <Button iconOnly aria-label="Đậm">
    <IconBold size={16} />
  </Button>
  <Button iconOnly aria-label="In nghiêng">
    <IconItalic size={16} />
  </Button>
  <Button iconOnly aria-label="Gạch chân">
    <IconUnderline size={16} />
  </Button>
</ButtonGroup>

Split button

Một thao tác chính và một menu thêm. Button solid không có viền, nên separator đánh dấu chỗ một Button kết thúc.

import { IconChevronDown, IconSparkles } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { ButtonGroup, ButtonGroupSeparator } from "@/components/ui/button-group"

<ButtonGroup aria-label="Publish" variant="solid">
  <Button leadingIcon={<IconSparkles size={16} />}>Publish</Button>
  <ButtonGroupSeparator />
  <Button iconOnly aria-label="More publish options">
    <IconChevronDown size={16} />
  </Button>
</ButtonGroup>

Cách nhau

import { IconArrowLeft, IconArrowRight } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup aria-label="Pages" attached={false}>
  <Button leadingIcon={<IconArrowLeft size={16} />}>Previous</Button>
  <Button trailingIcon={<IconArrowRight size={16} />}>Next</Button>
</ButtonGroup>

Chiều dọc

import { IconMinus, IconPlus } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup aria-label="Zoom" orientation="vertical">
  <Button iconOnly aria-label="Zoom in">
    <IconPlus size={16} />
  </Button>
  <Button iconOnly aria-label="Zoom out">
    <IconMinus size={16} />
  </Button>
</ButtonGroup>

Toàn chiều rộng

import { IconDownload, IconLink, IconMail } from "@tabler/icons-react"
import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup aria-label="Chia sẻ" fullWidth>
  <Button leadingIcon={<IconLink size={16} />}>Share link</Button>
  <Button leadingIcon={<IconMail size={16} />}>Email</Button>
  <Button leadingIcon={<IconDownload size={16} />}>Download</Button>
</ButtonGroup>

Nên và không nên

Nên

  • Gom hai đến năm thao tác liên quan chặt, như Rename, Duplicate và Archive, hoặc một thao tác chính và một menu thêm.
  • Đặt tên nhóm bằng aria-label hoặc một tiêu đề hiển thị qua aria-labelledby.
  • Dùng một variant cho cả nhóm. Dùng ButtonGroupSeparator giữa các Button solid nối liền.

Không nên

  • Đừng gom các thao tác không liên quan hoặc một thao tác chính với Cancel. Đặt các Button đó cạnh nhau.
  • Đừng dùng nhóm cho một lựa chọn luôn được chọn; dùng ToggleGroup hoặc Tabs.
  • Đừng đặt Button link trong nhóm.

Props

TênKiểuGiá trịMặc địnhMô tả
orientationenumhorizontal | verticalhorizontalMột hàng hoặc một cột Button.
attachedboolean-trueNối các Button thành một khối có cạnh chung. false thì cách chúng ra bằng khoảng spacing-sm.
sizeenumsm | md | lg | xllgSize của mọi Button trong nhóm, cùng các bước với Button: sm 28px, md 32px, lg 36px (mặc định của nhóm), xl 44px với chuột; trên cảm ứng md là 36px, lg 44px và xl 48px. Button tự đặt size thì giữ size của nó.
variantenumsecondary | solid | soft | ghost | destructive | destructive-soft | glossy | destructive-glossysecondaryVariant của mọi Button trong nhóm. Button tự đặt variant thì giữ variant của nó. Nhóm nối liền vẽ một shadow cho variant (shadow-low cho secondary và solid, shadow-med cho các bản glossy) thay vì mỗi Button một shadow. Đặt ButtonGroupSeparator giữa các Button solid nối liền.
fullWidthboolean-falseLấp đầy chiều rộng của container. Trong một hàng, các Button chia đều chiều rộng.

Slot

TênBắt buộcMô tả
childrencóCác Button, và ButtonGroupSeparator giữa các Button solid nối liền. Chỉ Button con trực tiếp mới nhận size và variant của nhóm.

Cấu tạo

PhầnMô tả
rootNhóm có tên. Nhóm không vẽ fill: các Button giữ fill, viền và motion của chúng. Khi nối liền, các Button bỏ shadow riêng và nhóm vẽ một shadow (theo bước của variant) quanh cả khối.
itemMột Button trong nhóm. Khi nối liền, chỉ các góc ngoài còn bo tròn và viền giữa hai Button gộp thành một đường.
separatorĐường 1px tùy chọn giữa hai Button solid, vốn không có viền để thấy chỗ một Button kết thúc.

Khả năng truy cập

Role: group

PhímHành động
Tab, Shift+TabĐi qua từng Button. Mỗi Button giữ điểm dừng tab riêng.
Space, EnterNhấn Button đang focus.
  • Nhóm cần aria-label hoặc aria-labelledby, để trình đọc màn hình đọc các Button thuộc về gì.
  • Mỗi Button giữ tên riêng. Button chỉ có icon cần aria-label.
  • Button đang focus nổi lên trên các Button bên cạnh, nên focus ring không bao giờ bị Button kế tiếp che.
  • ButtonGroupSeparator chỉ để trang trí và bị ẩn với trình đọc màn hình.
  • Với một lựa chọn luôn được chọn, dùng ToggleGroup hoặc Tabs: Button trong nhóm không có trạng thái pressed.

Cài đặt

npx werewolf-ui add button-group

Chạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.