# Button group

Joins related buttons, or a button and an input, into one connected control.

- **Import:** `import { ButtonGroup, ButtonGroupSeparator, ButtonGroupText } from "@booleanpress/ui/button-group"`
- **Page:** <https://ui.booleanpress.com/components/button-group> · @booleanpress/ui 0.1.0

## Usage

`ButtonGroup` removes the inner borders and corner radii of its children, so they read as one control. It lays out; it does not select. For a choice that stays pressed, use a toggle group.

```tsx
import { Button } from "@booleanpress/ui/button"
import { ButtonGroup } from "@booleanpress/ui/button-group"

export function Period() {
  return (
    <ButtonGroup aria-label="Log period">
      <Button variant="outline">Today</Button>
      <Button variant="outline">7 days</Button>
    </ButtonGroup>
  )
}
```

The parts are `ButtonGroup`, `ButtonGroupText` (a label or prefix drawn like a button), and `ButtonGroupSeparator` (a divider between two buttons that share a fill, as in a split button). A child can be a `Button`, an `Input` or a select trigger. Nest groups to space them apart. `orientation` is `horizontal` (default) or `vertical`.

## Examples

### Basic

Three related buttons as one control, named by `aria-label`.

```tsx
import { Button } from "@booleanpress/ui/button"
import { ButtonGroup } from "@booleanpress/ui/button-group"

export default function ButtonGroupBasic() {
  return (
    <ButtonGroup aria-label="Log period">
      <Button variant="outline">Today</Button>
      <Button variant="outline">7 days</Button>
      <Button variant="outline">30 days</Button>
    </ButtonGroup>
  )
}
```

### Vertical

`orientation="vertical"` stacks the buttons and joins them top to bottom.

```tsx
import { Button } from "@booleanpress/ui/button"
import { ButtonGroup } from "@booleanpress/ui/button-group"

export default function ButtonGroupVertical() {
  return (
    <ButtonGroup orientation="vertical" aria-label="Mailer actions">
      <Button variant="outline">Send test email</Button>
      <Button variant="outline">Duplicate</Button>
      <Button variant="outline">Disable</Button>
    </ButtonGroup>
  )
}
```

### Split button

A main action and a menu button, divided by `ButtonGroupSeparator`.

```tsx
import { ChevronDown } from "lucide-react"
import { Button } from "@booleanpress/ui/button"
import { ButtonGroup, ButtonGroupSeparator } from "@booleanpress/ui/button-group"

export default function ButtonGroupSplit() {
  return (
    <ButtonGroup aria-label="Save options">
      <Button variant="secondary">Save</Button>
      <ButtonGroupSeparator />
      <Button variant="secondary" size="icon" aria-label="More save options">
        <ChevronDown />
      </Button>
    </ButtonGroup>
  )
}
```

### With text and input

`ButtonGroupText` and an `Input` join a button in one row.

```tsx
import { Button } from "@booleanpress/ui/button"
import { ButtonGroup, ButtonGroupText } from "@booleanpress/ui/button-group"
import { Input } from "@booleanpress/ui/input"

export default function ButtonGroupWithTextAndInput() {
  return (
    <ButtonGroup className="w-full max-w-sm" aria-label="Test email">
      <ButtonGroupText>To</ButtonGroupText>
      <Input aria-label="Recipient" type="email" defaultValue="ops@example.com" />
      <Button variant="outline">Send</Button>
    </ButtonGroup>
  )
}
```

### Disabled

Disable one button; the others keep working and the group keeps its shape.

```tsx
import { Button } from "@booleanpress/ui/button"
import { ButtonGroup } from "@booleanpress/ui/button-group"

export default function ButtonGroupDisabled() {
  return (
    <ButtonGroup aria-label="Page navigation">
      <Button variant="outline" disabled>
        Previous
      </Button>
      <Button variant="outline">Next</Button>
    </ButtonGroup>
  )
}
```

## Accessibility

**Semantics.** A `div` with `role="group"`. `data-orientation` is set when you pass `orientation`. The separator is decorative and hidden from assistive technology.

**Labels.** Name the group with `aria-label` or `aria-labelledby` when the buttons need shared context ("Log period"). Name every icon-only button and every `Input` inside it.

**Focus.** Each child keeps its own tab stop. The focused child is raised above its neighbours, so its focus ring is not cut off by the next button.

**Known limits.**

- The group adds no arrow-key navigation. If you want the toolbar pattern (one tab stop, arrow keys between buttons), use a toolbar or a toggle group instead.
- It does not track a selected button. Mark a current choice yourself, for example with `aria-pressed`.

### Keyboard

| Key | Behaviour |
| --- | --- |

## API

### ButtonGroup

Renders a `div` and passes it every other prop.

### ButtonGroupSeparator

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` |  |  |
| `decorative` | `boolean` |  | Whether or not the component is purely decorative. When true, accessibility-related attributes are updated so that that the rendered element is removed from the accessibility tree. |
| `orientation` | `"horizontal" \| "vertical"` | `vertical` | Either `vertical` or `horizontal`. Defaults to `horizontal`. |

### ButtonGroupText

Renders a `div` and passes it every other prop.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Render the child element instead, with this part's classes merged onto it, for a `Label` that sits in the group. |

**Also exported:** `buttonGroupVariants`, the class names of ButtonGroup's variants and sizes (`cva`), to give another element the same look.

Every part takes `className`, merged with its defaults by `cn()`, and `ref`, which reaches the element it renders.

**Data attributes:** `data-slot="button-group"` (ButtonGroup), `data-slot="button-group-separator"` (ButtonGroupSeparator), and `data-orientation`.

## Theming

| Token | Used for |
| --- | --- |
| `--input` | background |
| `--muted` | background |
