# ButtonGroup

A named row or column of related Buttons, joined into one block with shared edges or spaced apart. The group sets one size and variant for its Buttons.

**Dependencies:** npm: 1 direct, 4 total; registry: 3 direct, 3 total.

## Usage

### When to use

- Keep two to five related actions together, such as Copy, Edit and Delete in a toolbar.
- A main action with a menu of more next to it (a split button).

### When not to use

- A choice that stays selected, such as a view or alignment. Use ToggleGroup or Tabs.
- Unrelated actions, or a main action next to Cancel. Place the Buttons side by side.
- Moving between pages of results. Use Pagination.

## Variants

### orientation

A row or a column of Buttons.

Values: `horizontal`, `vertical`. Default: `horizontal`.

### size

The Button size for every Button in the group, the same steps as Button: sm 28px, md 32px, lg 36px (the group default), xl 44px with a mouse; on touch md is 36px, lg 44px and xl 48px. A Button that sets its own size keeps it.

Values: `sm`, `md`, `lg`, `xl`. Default: `lg`.

### variant

The Button variant for every Button in the group. A Button that sets its own variant keeps it. An attached group draws one shadow for the variant (shadow-low for secondary and solid, shadow-med for the glossy ones) instead of one per Button. Put a ButtonGroupSeparator between attached solid Buttons.

Values: `secondary`, `solid`, `soft`, `ghost`, `destructive`, `destructive-soft`, `glossy`, `destructive-glossy`. Default: `secondary`.

## Examples

### Attached actions

```tsx
<ButtonGroup aria-label="File actions">
  <Button>Rename</Button>
  <Button>Duplicate</Button>
  <Button>Archive</Button>
</ButtonGroup>
```

### Icons and labels

Icon-only Buttons carry their own name.

```tsx
<ButtonGroup aria-label="Text formatting">
  <Button iconOnly aria-label="Bold">
    <IconBold size={16} />
  </Button>
  <Button iconOnly aria-label="Italic">
    <IconItalic size={16} />
  </Button>
  <Button iconOnly aria-label="Underline">
    <IconUnderline size={16} />
  </Button>
</ButtonGroup>
```

### Split button

A main action and a menu with more. Solid Buttons have no border, so a separator marks where one ends.

```tsx
<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>
```

### Spaced apart

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

### Vertical

```tsx
<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>
```

### Full width

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

## Do and don't

### Do

- Group two to five closely related actions, such as Rename, Duplicate and Archive, or a main action and a menu with more.
- Name the group with aria-label or a visible heading through aria-labelledby.
- Use one variant for the whole group. Use a ButtonGroupSeparator between attached solid Buttons.

### Don't

- Do not group unrelated actions or a main action with a Cancel. Place those Buttons side by side instead.
- Do not use a group for a choice that stays selected; use ToggleGroup or Tabs.
- Do not put a link Button in a group.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `orientation` | `enum` | `horizontal`, `vertical` | `horizontal` | A row or a column of Buttons. |
| `attached` | `boolean` |  | `true` | Joins the Buttons into one block with shared edges. false spaces them out with a spacing-sm gap. |
| `size` | `enum` | `sm`, `md`, `lg`, `xl` | `lg` | The Button size for every Button in the group, the same steps as Button: sm 28px, md 32px, lg 36px (the group default), xl 44px with a mouse; on touch md is 36px, lg 44px and xl 48px. A Button that sets its own size keeps it. |
| `variant` | `enum` | `secondary`, `solid`, `soft`, `ghost`, `destructive`, `destructive-soft`, `glossy`, `destructive-glossy` | `secondary` | The Button variant for every Button in the group. A Button that sets its own variant keeps it. An attached group draws one shadow for the variant (shadow-low for secondary and solid, shadow-med for the glossy ones) instead of one per Button. Put a ButtonGroupSeparator between attached solid Buttons. |
| `fullWidth` | `boolean` |  | `false` | Fills the width of its container. In a row the Buttons share the width equally. |

### Slots

| Name | Required | Description |
| --- | --- | --- |
| `children` | yes | Buttons, and ButtonGroupSeparator between attached solid Buttons. Only direct Button children take the group size and variant. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | The named group. It draws no fill: the Buttons keep their own fill, border and motion. Attached, the Buttons drop their own shadows and the group draws one shadow (the variant's step) around the whole block. |
| `item` | A Button inside the group. Attached, only the outer corners stay round and neighbouring borders collapse into one line. |
| `separator` | An optional 1px line between two solid Buttons, which have no border to show where one ends. |

## Accessibility

Role: `group`

| Keys | Action |
| --- | --- |
| `Tab, Shift+Tab` | Moves through the Buttons one by one. Every Button keeps its own tab stop. |
| `Space, Enter` | Presses the focused Button. |

- The group requires aria-label or aria-labelledby, so screen readers announce what the Buttons belong to.
- Every Button keeps its own name. An icon-only Button requires aria-label.
- The focused Button rises above its neighbours, so its focus ring is never cut by the next Button.
- ButtonGroupSeparator is decorative and hidden from screen readers.
- For a choice that stays selected, use ToggleGroup or Tabs: the Buttons of a group carry no pressed state.

## Install

```bash
npx werewolf-ui add button-group
```

Run `npx werewolf-ui init` once in your app before adding components. Init sets up tokens, their CSS import and agent rules. Add installs this component and its dependencies while preserving your theme. See [Installation](https://www.werewolf-ui.dev/docs/installation.md) for requirements and the alternative registry setup.
