<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# ButtonGroup

Related buttons joined into one control, such as Previous, a page number and Next, or a split button. Only the outer corners are round, borders are shared, and buttons without a border get a separator. Each child keeps its own `variant`, `tone` and `size`, and the group has a name for screen readers.

```tsx
import { ButtonGroup } from "@/components/ouro/button-group/button-group";
```

## Example

```tsx
<ButtonGroup label="Pagination">
  <Button variant="outline" tone="secondary">Previous</Button>
  <Button variant="outline" tone="secondary">Next</Button>
</ButtonGroup>
```

## Use instead when

- Use `ToggleGroup` instead when the buttons stay pressed and share one value, and a plain row (`<div className="flex gap-2">`) for buttons that are not one control.

## Props

Type: `ButtonGroupProps`.

| Prop | Type | Description |
| --- | --- | --- |
| `children` (required) | `ReactNode` | The buttons, in order: `Button`s or `Toggle`s, each with its own `variant`, `tone` and `size`. |
| `className` | `string` | Layout only: margins, width, grid placement (`mt-4`). Appearance classes warn in development. |
| `fullWidth` | `boolean` | Stretches the group to the width of its container, with the buttons sharing it equally. |
| `label` (required) | `string` | Names the group for screen readers ("Pagination", "Text alignment"). It is not shown. |
| `ref` | `Ref<HTMLDivElement>` | The group element (`role="group"`). |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `isAttached`: Not a prop. A ButtonGroup always joins its buttons.
- `orientation`: Not a prop. A ButtonGroup is a row; stack buttons in a grid: `<div className="grid gap-2">`.
- `size`: Not a prop. Each Button keeps its own: `<Button size="sm">`.
- `tone`: Not a prop. Each Button keeps its own: `<Button tone="secondary">`.
- `variant`: Not a prop. Each Button keeps its own: `<Button variant="outline">`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: ButtonGroup merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

[^layout-classes]: test:registry/ouro/components/ouro/button-group/button-group.test.tsx::ButtonGroup > forwards its ref and lets layout classes win verify:testExists(registry/ouro/components/ouro/button-group/button-group.test.tsx::ButtonGroup > forwards its ref and lets layout classes win)
