# Toggle Group

Group related pressed-state buttons.

Text alignment

[Complete TSX file](/examples/toggle-group/default.tsx)

```tsx
"use client";

import {
  AlignCenterIcon,
  AlignJustifyIcon,
  AlignLeftIcon,
  AlignRightIcon,
} from "lucide-react";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  return (
    <ToggleGroup
      aria-label="Text alignment"
      defaultValue={["left"]}
      variant="outline"
    >
      <ToggleGroupItem aria-label="Align left" value="left">
        <AlignLeftIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Align center" value="center">
        <AlignCenterIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Align right" value="right">
        <AlignRightIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Justify" value="justify">
        <AlignJustifyIcon />
      </ToggleGroupItem>
    </ToggleGroup>
  );
}
```

## Installation

Complete [one-time setup](/docs/installation/) first.

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/toggle-group
```

With npm: `npx shadcn@4.18.0 add @siteplane/toggle-group`. [Registry JSON](/registry/toggle-group.json) lists source files and dependencies.

For this page’s examples, also install:

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/input
```

Field is installed with Input.

## Usage

```tsx
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

<ToggleGroup aria-label="View" defaultValue={["grid"]}>
  <ToggleGroupItem value="grid">Grid</ToggleGroupItem>
  <ToggleGroupItem value="list">List</ToggleGroupItem>
</ToggleGroup>;
```

## Composition

```text
ToggleGroup
├── ToggleGroupItem
├── ToggleGroupSeparator
└── ToggleGroupItem
```

## Multiple selection

Set `multiple` to allow several pressed items. `value` is always an array, in single and multiple mode.

Formatting options with multiple selection

[Complete TSX file](/examples/toggle-group/controlled.tsx)

```tsx
"use client";

import { useState } from "react";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  const [value, setValue] = useState<string[]>(["bold"]);
  return (
    <ToggleGroup
      aria-label="Text formatting"
      multiple
      onValueChange={setValue}
      value={value}
    >
      <ToggleGroupItem value="bold">Bold</ToggleGroupItem>
      <ToggleGroupItem value="italic">Italic</ToggleGroupItem>
      <ToggleGroupItem disabled value="underline">
        Underline
      </ToggleGroupItem>
    </ToggleGroup>
  );
}
```

## With label

Name the group with a visible `FieldLabel` and point `aria-labelledby` at it. To keep one option selected, ignore empty values in `onValueChange`.

View switcher with label

[Complete TSX file](/examples/toggle-group/with-label.tsx)

```tsx
"use client";

import { LayoutGridIcon, ListIcon } from "lucide-react";
import { useId, useState } from "react";
import { Field, FieldLabel } from "@/siteplane/components/field";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  const labelId = useId();
  const [view, setView] = useState<string[]>(["grid"]);
  return (
    <Field>
      <FieldLabel id={labelId}>View</FieldLabel>
      <ToggleGroup
        aria-labelledby={labelId}
        onValueChange={(next) => {
          if (next.length > 0) setView(next);
        }}
        value={view}
        variant="outline"
      >
        <ToggleGroupItem value="grid">
          <LayoutGridIcon />
          Grid
        </ToggleGroupItem>
        <ToggleGroupItem value="list">
          <ListIcon />
          List
        </ToggleGroupItem>
      </ToggleGroup>
    </Field>
  );
}
```

## With separators

Place a `ToggleGroupSeparator` between sets of related items. It is vertical by default; in a vertical group, set `orientation="horizontal"`. Outline groups already draw a divider between every item.

Formatting group with a separator

[Complete TSX file](/examples/toggle-group/with-separators.tsx)

```tsx
"use client";

import { BoldIcon, ItalicIcon, StrikethroughIcon } from "lucide-react";
import {
  ToggleGroup,
  ToggleGroupItem,
  ToggleGroupSeparator,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  return (
    <ToggleGroup aria-label="Text formatting" defaultValue={["bold"]} multiple>
      <ToggleGroupItem aria-label="Bold" value="bold">
        <BoldIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Italic" value="italic">
        <ItalicIcon />
      </ToggleGroupItem>
      <ToggleGroupSeparator />
      <ToggleGroupItem aria-label="Strikethrough" value="strikethrough">
        <StrikethroughIcon />
      </ToggleGroupItem>
    </ToggleGroup>
  );
}
```

## Vertical

Set `orientation="vertical"` to stack the items; arrow-key navigation follows the orientation.

Vertical toggle group

[Complete TSX file](/examples/toggle-group/layout.tsx)

```tsx
"use client";

import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  return (
    <ToggleGroup
      aria-label="Text formatting"
      defaultValue={["bold", "italic"]}
      multiple
      orientation="vertical"
    >
      <ToggleGroupItem aria-label="Bold" value="bold">
        <BoldIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Italic" value="italic">
        <ItalicIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Underline" value="underline">
        <UnderlineIcon />
      </ToggleGroupItem>
    </ToggleGroup>
  );
}
```

## Sizes

Set `size` (and `variant`) on the group; every item inherits it.

Toggle group sizes

[Complete TSX file](/examples/toggle-group/sizes.tsx)

```tsx
"use client";

import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

const sizes = [
  ["sm", "small"],
  ["md", "medium"],
  ["lg", "large"],
  ["xl", "extra large"],
] as const;

export default function Example() {
  return (
    <div className="grid gap-3">
      {sizes.map(([size, name]) => (
        <ToggleGroup
          aria-label={`View, ${name}`}
          defaultValue={["list"]}
          key={size}
          size={size}
        >
          <ToggleGroupItem value="list">List</ToggleGroupItem>
          <ToggleGroupItem value="grid">Grid</ToggleGroupItem>
        </ToggleGroup>
      ))}
    </div>
  );
}
```

## API reference

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| variant | default \| outline | default | Item surface. |
| size | sm \| md \| lg \| xl | provider / lg | Item size. |
| multiple | boolean | false | Allow multiple pressed items. |
| orientation | horizontal \| vertical | horizontal | Layout and keyboard orientation. |
| width | auto \| full | auto | Fit or full width. |
| wrap | boolean | false | Allow wrapping. |
| value / defaultValue | string[] | uncontrolled | Selection. |
| onValueChange | (values, eventDetails) => void | unset | Selection callback. |
| ToggleGroupItem.grow | boolean | false | Flex-grow item. |
| ToggleGroupItem.maxWidth | label | unset | Cap at max-w-40 and truncate label. |
| ToggleGroupItem.padding | default \| comfortable | default | Padding. |
| ToggleGroupSeparator.orientation | horizontal \| vertical | vertical | Divider direction. |

Items accept Base UI Toggle props including value and disabled and take the
group's size and variant. Separator accepts Separator props and draws the
divider between joined items. `ToggleGroupPrimitive` exposes the Base UI namespace. `ToggleGroupContext`
defaults to single false, inherited size and variant default. Other root props and
keyboard behavior follow [Base UI Toggle
Group](https://base-ui.com/react/components/toggle-group).

[Read the installed source](/source/toggle-group).

## Usage notes

Tab enters the group; arrow keys move among items. Unlike RadioGroup, a single selected item can be cleared. Use Tabs for associated content panels.
