# Toggle group

A row of toggles in Candor's theme: one choice from a few (`type="single"`) or several at once (`type="multiple"`). Arrow keys move between items, Home and End jump to the ends. Nothing is pressed until the app says so or the person presses it.

- Registry name: `toggle-group` (`@candor/toggle-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/toggle-group

## Install

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

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/toggle-group`.
It brings in: locked, motion, render-prop, toggle, tokens, utils.
npm packages: class-variance-authority@^0.7.1, radix-ui@^1.8.1.

## Example

```tsx
"use client"

import * as React from "react"
import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon } from "lucide-react"
import { Toggle } from "@/components/candor/ui/toggle"
import { ToggleGroup, ToggleGroupItem } from "@/components/candor/ui/toggle-group"
import { TooltipProvider } from "@/components/candor/ui/tooltip"

export default function Example() {
  // Nothing is chosen until the person chooses; the app decides what an empty value means.
  const [view, setView] = React.useState("")
  return (
    <TooltipProvider>
      <div className="flex flex-col items-start gap-6">
        <ToggleGroup type="single" value={view} onValueChange={setView} aria-label="Table density">
          <ToggleGroupItem value="compact">Compact</ToggleGroupItem>
          <ToggleGroupItem value="comfortable">Comfortable</ToggleGroupItem>
          <ToggleGroupItem value="spacious" locked="Spacious needs the wide layout.">
            Spacious
          </ToggleGroupItem>
        </ToggleGroup>

        <ToggleGroup type="multiple" variant="outline" aria-label="Text style">
          <ToggleGroupItem value="left" aria-label="Align left">
            <AlignLeftIcon />
          </ToggleGroupItem>
          <ToggleGroupItem value="center" aria-label="Align centre">
            <AlignCenterIcon />
          </ToggleGroupItem>
          <ToggleGroupItem value="right" aria-label="Align right">
            <AlignRightIcon />
          </ToggleGroupItem>
        </ToggleGroup>

        <Toggle variant="outline">Wrap long lines</Toggle>
      </div>
    </TooltipProvider>
  )
}
```

## <ToggleGroup>

Props:

- `variant?: "default" | "outline"` (default `"default"`): Which variant: one of `toggleVariants`'s styles.
- `size?: "default" | "sm" | "lg"` (default `"default"`): Which size: one of `toggleVariants`'s styles.
- `indicator?: boolean | undefined` (default `true`): Slides a highlight behind the pressed item in a single-choice group. Defaults to true; a multiple-choice group has no single item to point at, so it only changes the pressed items' colours.

Also takes the props of `React.ComponentProps<typeof ToggleGroupPrimitive.Root>`.

## <ToggleGroupItem>

Props:

- `variant?: "default" | "outline"` (default `"default"`): Which variant: one of `toggleVariants`'s styles.
- `size?: "default" | "sm" | "lg"` (default `"default"`): Which size: one of `toggleVariants`'s styles.
- `locked?: string | undefined`: Why this item can't be chosen right now. When set, it stays in the arrow-key order and is marked `aria-disabled`, pressing it changes nothing, and the reason is shown on hover and focus and read to screen readers (see `Locked`).

Also takes the props of `React.ComponentProps<typeof ToggleGroupPrimitive.Item>`, `RenderProp`.

## Motion

- **indicator** (move): In a single-choice group the highlight slides to the item the person chose. It is placed without sliding on first draw and when it appears after nothing was chosen, and when the pressed item changes for a reason other than a press it still slides, because that is a change the person should see.

Set with `--cd-motion-toggle-group-<moment>-*` in your brand file; the families are in the design reference.

## 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`.
