# Button group

Buttons joined into one control: shared edges, inner corners squared, one border between each pair. Use it for a few related actions that read as a set (a split button, Previous and Next, zoom out and in). Each button stays its own tab stop, as buttons are: a button group has no arrow-key model (a toolbar does).

The group is `role="group"`; give it a `label` when its buttons don't explain themselves together ("Zoom", "Pagination"). The joins use logical sides, so a row joins correctly right to left, and they reach a button inside `Locked` too, so a locked button keeps its place in the join and says why.

- Registry name: `button-group` (`@candor/button-group`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/button-group

## Install

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

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/button-group`.
It brings in: separator, tokens, utils.
npm packages: @base-ui/react@^1.9.0.

## Example

```tsx
"use client"

import { ChevronLeft, ChevronRight, Minus, Plus } from "lucide-react"
import { Button } from "@/components/candor/ui/button"
import { ButtonGroup, ButtonGroupText } from "@/components/candor/ui/button-group"
import { Locked } from "@/components/candor/locked"
import { TooltipProvider } from "@/components/candor/ui/tooltip"

// Name a group whose buttons don't explain themselves together. A locked button keeps its place in the join and says
// why. Each button is its own tab stop; for arrow keys between buttons, use a toolbar.
export default function Example() {
  return (
    <TooltipProvider>
      <div className="flex flex-wrap items-center gap-4">
        <ButtonGroup label="Pages">
          <Button variant="outline">
            <ChevronLeft aria-hidden />
            Previous
          </Button>
          <ButtonGroupText>Page 5 of 5</ButtonGroupText>
          <Locked reason="This is the last page">
            <Button variant="outline">
              Next
              <ChevronRight aria-hidden />
            </Button>
          </Locked>
        </ButtonGroup>
        <ButtonGroup label="Zoom">
          <Button variant="outline" size="icon" aria-label="Zoom out">
            <Minus aria-hidden />
          </Button>
          <Button variant="outline" size="icon" aria-label="Zoom in">
            <Plus aria-hidden />
          </Button>
        </ButtonGroup>
      </div>
    </TooltipProvider>
  )
}
```

## <ButtonGroup>

Props:

- `label?: string | undefined`: The group's name, read before its buttons. Give one when the buttons don't explain themselves together.
- `orientation?: "horizontal" | "vertical" | undefined` (default `"horizontal"`): Whether the buttons sit in a row or a column. Defaults to a row.
- `className?: string | undefined`: Classes, merged with Candor's.
- `children: React.ReactNode`: The buttons, and any `ButtonGroupSeparator` or `ButtonGroupText` between them.

## <ButtonGroupSeparator>

A line between two parts of a `ButtonGroup`, for buttons drawn without a border of their own (`variant="secondary"` or `"ghost"`). It runs across the group, following the group's orientation: vertical in a row, horizontal in a column. It is decoration only.

Props:

- `orientation?: "horizontal" | "vertical" | undefined`: Which way the line runs. Defaults to across the group: `vertical` in a row, `horizontal` in a column.
- `className?: string | undefined`: Classes, merged with Candor's.

## <ButtonGroupText>

A cell of text in a `ButtonGroup`'s style: a unit, a label or a count joined to the buttons beside it ("Page 2 of 5"). It is a `div` by default; `render` draws another element (a `<label>` for an input in the group) with its styles.

Props:

- `render?: useRender.RenderProp | undefined`: Draws this element in place of the `div`, with the cell's styles: `render={<label htmlFor="q" />}`.
- `className?: string | undefined`: Classes, merged with Candor's.
- `children?: React.ReactNode | undefined`: The text, and an icon if it helps.

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
