# ToggleGroup (/docs/toggle-group)





## API Reference [#api-reference]

<BaseUIReference href="https://base-ui.com/react/components/toggle-group" />

## Basic [#basic]

<Preview cssProperties="toggleGroupPlaygroundCssProperties">
  <ToggleGroupExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";

          export function BasicToggleGroupDemo() {
            return (
              <ToggleGroup defaultValue={["left"]} aria-label="Text alignment">
                {items.map((item) => (
                  <ToggleGroupItem key={item.value} value={item.value}>
                    {item.label}
                  </ToggleGroupItem>
                ))}
              </ToggleGroup>
            );
          }
        `}
  </Preview.Code>

  <Preview.Data>
    {`
          const items = [
            { value: "left", label: "Left" },
            { value: "center", label: "Center" },
            { value: "right", label: "Right" },
          ];
        `}
  </Preview.Data>

  <Preview.CSSProperties>
    {(context) => <ToggleGroupCssPropertiesPanel {...context} />}
  </Preview.CSSProperties>

  <Preview.CSSPlayground>
    {(context) => <ToggleGroupCssPlaygroundPanel {...context} />}
  </Preview.CSSPlayground>
</Preview>

## Anatomy [#anatomy]

`ToggleGroup` is a single root that coordinates a set of `ToggleGroupItem` buttons. Keep every
choice inside the same group so keyboard navigation, pressed state, and selection rules (`multiple`
or single-select) stay consistent.

```text
ToggleGroup
└─ ToggleGroupItem[value]
   └─ label or icon content
```

```tsx
<ToggleGroup defaultValue={['left']} aria-label="Text alignment">
  <ToggleGroupItem value="left">Left</ToggleGroupItem>
  <ToggleGroupItem value="center">Center</ToggleGroupItem>
  <ToggleGroupItem value="right">Right</ToggleGroupItem>
</ToggleGroup>
```

| Part              | Role                                                                                                  |
| ----------------- | ----------------------------------------------------------------------------------------------------- |
| `ToggleGroup`     | Root state machine. Controls selected values, arrow-key navigation, and orientation.                  |
| `ToggleGroupItem` | Interactive toggle button with a unique `value` used by `defaultValue`, `value`, and `onValueChange`. |

`ToggleGroup` does not include service layers such as `portal`, `backdrop`, `viewport`, or hidden
internal slots. In most cases, keep structure and behavior defaults and style the visible parts
with `className` on the group and on each `ToggleGroupItem`.

`ToggleGroupItem` renders `Toggle`, so item-level styling also supports the `Toggle` CSS variables
(`--toggle-*`). Use `--toggle-group-*` for the group container and `--toggle-*` for item states.

```css
.filterGroup {
  --toggle-group-bg: transparent;
  --toggle-group-border-color: transparent;
  --toggle-group-padding: 0;
}

.filterItem {
  --toggle-ghost-bg-hover: var(--color-accent);
  --toggle-ghost-bg-pressed: var(--color-primary);
  --toggle-ghost-color-pressed: var(--color-primary-foreground);
}
```

## Composition [#composition]

Use `ToggleGroup` for root state and behavior props such as `value`, `defaultValue`,
`onValueChange`, `multiple`, `orientation`, `disabled`, and `loopFocus`.

Use group-level props (`variant`, `size`, `className`) when all items should share one setup.
Override a specific `ToggleGroupItem` with its own `variant`, `size`, or `className` when one
option needs a different presentation.

## Examples [#examples]

### Multiple [#multiple]

Use `multiple` when more than one item can be pressed at the same time.

<Preview>
  <ToggleGroupMultipleExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";
          import styles from "./toggle-group.module.css";

          export function MultipleToggleGroupDemo() {
            return (
              <ToggleGroup
                multiple
                defaultValue={["bold", "italic"]}
                aria-label="Text formatting"
                size="icon-md"
              >
                <ToggleGroupItem value="bold" aria-label="Bold">
                  <strong>B</strong>
                </ToggleGroupItem>
                <ToggleGroupItem value="italic" aria-label="Italic">
                  <em>I</em>
                </ToggleGroupItem>
                <ToggleGroupItem value="underline" aria-label="Underline">
                  <span className={styles.underline}>U</span>
                </ToggleGroupItem>
              </ToggleGroup>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .underline {
            text-decoration: underline;
          }
        `}
  </Preview.CSS>
</Preview>

### Variants [#variants]

Use `variant` on the group to apply the same visual treatment to every item.

<Preview>
  <ToggleGroupVariantsExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";
          import styles from "./toggle-group.module.css";

          export function ToggleGroupVariantsDemo() {
            return (
              <div className={styles.stack}>
                {variants.map((variant) => (
                  <ToggleGroup
                    key={variant.value}
                    defaultValue={["one"]}
                    aria-label={variant.label}
                    variant={variant.value}
                  >
                    {items.map((item) => (
                      <ToggleGroupItem key={item.value} value={item.value}>
                        {item.label}
                      </ToggleGroupItem>
                    ))}
                  </ToggleGroup>
                ))}
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>

  <Preview.Data>
    {`
          const variants = [
            { value: "default", label: "Default variant" },
            { value: "outline", label: "Outline variant" },
            { value: "ghost", label: "Ghost variant" },
          ] as const;

          const items = [
            { value: "one", label: "One" },
            { value: "two", label: "Two" },
            { value: "three", label: "Three" },
          ];
        `}
  </Preview.Data>
</Preview>

### Sizes [#sizes]

Use text sizes for labeled groups and icon sizes for compact toolbar controls.

<Preview>
  <ToggleGroupSizesExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";
          import styles from "./toggle-group.module.css";

          export function ToggleGroupSizesDemo() {
            return (
              <div className={styles.stack}>
                {sizes.map((group) => (
                  <ToggleGroup
                    key={group.size}
                    defaultValue={[group.items[0].value]}
                    aria-label={group.label}
                    size={group.size}
                  >
                    {group.items.map((item) => (
                      <ToggleGroupItem key={item.value} value={item.value}>
                        {item.label}
                      </ToggleGroupItem>
                    ))}
                  </ToggleGroup>
                ))}
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>

  <Preview.Data>
    {`
          const sizes = [
            {
              size: "xs",
              label: "Extra-small size",
              items: [
                { value: "xs", label: "XS" },
                { value: "sm", label: "SM" },
              ],
            },
            {
              size: "sm",
              label: "Small size",
              items: [
                { value: "sm", label: "Small" },
                { value: "md", label: "Medium" },
              ],
            },
            {
              size: "md",
              label: "Medium size",
              items: [
                { value: "md", label: "Medium" },
                { value: "lg", label: "Large" },
              ],
            },
            {
              size: "lg",
              label: "Large size",
              items: [
                { value: "lg", label: "Large" },
                { value: "xl", label: "Extra" },
              ],
            },
          ] as const;
        `}
  </Preview.Data>
</Preview>

### Vertical [#vertical]

Set `orientation="vertical"` when the choices should stack in a column.

<Preview>
  <ToggleGroupVerticalExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";

          export function VerticalToggleGroupDemo() {
            return (
              <ToggleGroup
                defaultValue={["list"]}
                orientation="vertical"
                aria-label="View mode"
                variant="outline"
              >
                {items.map((item) => (
                  <ToggleGroupItem key={item.value} value={item.value}>
                    {item.label}
                  </ToggleGroupItem>
                ))}
              </ToggleGroup>
            );
          }
        `}
  </Preview.Code>

  <Preview.Data>
    {`
          const items = [
            { value: "list", label: "List" },
            { value: "grid", label: "Grid" },
            { value: "map", label: "Map" },
          ];
        `}
  </Preview.Data>
</Preview>

### Disabled [#disabled]

Use `disabled` on the group or on a specific item to prevent interaction.

<Preview>
  <ToggleGroupDisabledExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";
          import styles from "./toggle-group.module.css";

          export function DisabledToggleGroupDemo() {
            return (
              <div className={styles.row}>
                <ToggleGroup defaultValue={["one"]} aria-label="Disabled group" disabled>
                  {items.map((item) => (
                    <ToggleGroupItem key={item.value} value={item.value}>
                      {item.label}
                    </ToggleGroupItem>
                  ))}
                </ToggleGroup>
                <ToggleGroup defaultValue={["one"]} aria-label="Disabled item">
                  {items.map((item) => (
                    <ToggleGroupItem key={item.value} value={item.value} disabled={item.disabled}>
                      {item.label}
                    </ToggleGroupItem>
                  ))}
                </ToggleGroup>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .row {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            justify-content: center;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>

  <Preview.Data>
    {`
          const items = [
            { value: "one", label: "One" },
            { value: "two", label: "Two", disabled: true },
          ];
        `}
  </Preview.Data>
</Preview>

### Loop Focus [#loop-focus]

Set `loopFocus={false}` when arrow-key navigation should stop at the first or last item.

<Preview>
  <ToggleGroupLoopFocusExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";

          export function LoopFocusToggleGroupDemo() {
            return (
              <ToggleGroup defaultValue={["day"]} aria-label="Schedule range" loopFocus={false}>
                {items.map((item) => (
                  <ToggleGroupItem key={item.value} value={item.value}>
                    {item.label}
                  </ToggleGroupItem>
                ))}
              </ToggleGroup>
            );
          }
        `}
  </Preview.Code>

  <Preview.Data>
    {`
          const items = [
            { value: "day", label: "Day" },
            { value: "week", label: "Week" },
            { value: "month", label: "Month" },
          ];
        `}
  </Preview.Data>
</Preview>

### Controlled [#controlled]

Control `value` from React state when the group needs to coordinate with other UI.

<Preview>
  <ControlledToggleGroupExample />

  <Preview.Code>
    {`
          import { BellIcon, CheckSmallIcon, StarIcon, ToggleGroup, ToggleGroupItem } from "moduix";
          import { useState } from "react";
          import styles from "./toggle-group.module.css";

          export function ControlledToggleGroupDemo() {
            const [value, setValue] = useState(["favorites"] as string[]);

            return (
              <div className={styles.stack}>
                <ToggleGroup
                  value={value}
                  onValueChange={setValue}
                  aria-label="Controlled options"
                  multiple
                >
                  <ToggleGroupItem value="favorites">
                    {value.includes("favorites") ? <CheckSmallIcon /> : <StarIcon />}
                    Favorites
                  </ToggleGroupItem>
                  <ToggleGroupItem value="alerts">
                    <BellIcon />
                    Alerts
                  </ToggleGroupItem>
                </ToggleGroup>
                <span className={styles.hint}>Current value: {value.join(", ") || "empty"}</span>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: var(--spacing-3);
          }

          .hint {
            color: var(--color-muted-foreground);
            font-size: var(--text-xs);
            line-height: var(--line-height-text-xs);
          }
        `}
  </Preview.CSS>
</Preview>

### Icons [#icons]

Pass icons as children. Icon-only items must include an accessible label.

<Preview>
  <ToggleGroupIconExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";
          import styles from "./toggle-group.module.css";

          export function IconToggleGroupDemo() {
            return (
              <ToggleGroup defaultValue={["left"]} aria-label="Text alignment" size="icon-md">
                <ToggleGroupItem value="left" aria-label="Align left">
                  <svg className={styles.customIcon} viewBox="0 0 16 16" fill="none" aria-hidden="true">
                    <path
                      d="M2.5 3.5h11M2.5 8h8M2.5 12.5h11"
                      stroke="currentColor"
                      strokeWidth="1.5"
                      strokeLinecap="round"
                    />
                  </svg>
                </ToggleGroupItem>
                <ToggleGroupItem value="center" aria-label="Align center">
                  <svg className={styles.customIcon} viewBox="0 0 16 16" fill="none" aria-hidden="true">
                    <path
                      d="M2.5 3.5h11M4 8h8M2.5 12.5h11"
                      stroke="currentColor"
                      strokeWidth="1.5"
                      strokeLinecap="round"
                    />
                  </svg>
                </ToggleGroupItem>
                <ToggleGroupItem value="right" aria-label="Align right">
                  <svg className={styles.customIcon} viewBox="0 0 16 16" fill="none" aria-hidden="true">
                    <path
                      d="M2.5 3.5h11M5.5 8h8M2.5 12.5h11"
                      stroke="currentColor"
                      strokeWidth="1.5"
                      strokeLinecap="round"
                    />
                  </svg>
                </ToggleGroupItem>
              </ToggleGroup>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .customIcon {
            width: 1rem;
            height: 1rem;
          }
        `}
  </Preview.CSS>
</Preview>

### Custom Styles [#custom-styles]

Pass `className` to the group and items when styling with CSS Modules, Tailwind CSS, or CSS-in-JS.
Use `--toggle-group-*` to style the group container and `--toggle-*` to style `ToggleGroupItem`
states such as hover and pressed.

<Preview>
  <CustomStylesToggleGroupExample />

  <Preview.Code>
    {`
          import { ToggleGroup, ToggleGroupItem } from "moduix";
          import styles from "./toggle-group.module.css";

          export function CustomStylesToggleGroupDemo() {
            return (
              <ToggleGroup
                defaultValue={["day"]}
                aria-label="Schedule density"
                className={styles.customGroup}
              >
                {items.map((item) => (
                  <ToggleGroupItem key={item.value} value={item.value} className={styles.customItem}>
                    {item.label}
                  </ToggleGroupItem>
                ))}
              </ToggleGroup>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .customGroup {
            --toggle-group-bg: color-mix(in oklab, var(--color-primary) 8%, transparent);
            --toggle-group-border-color: color-mix(in oklab, var(--color-primary) 38%, var(--color-border));
            --toggle-group-gap: var(--spacing-1);
            --toggle-group-padding: var(--spacing-1);
            --toggle-group-radius: var(--radius-md);
            --toggle-default-bg-pressed: var(--color-primary);
            --toggle-default-border-color-pressed: var(--color-primary);
            --toggle-default-color-pressed: var(--color-primary-foreground);
          }

          .customItem {
            --toggle-group-item-radius: var(--radius-sm);
            --toggle-padding-x-md: var(--spacing-3);
          }
        `}
  </Preview.CSS>

  <Preview.Data>
    {`
          const items = [
            { value: "day", label: "Day" },
            { value: "week", label: "Week" },
            { value: "month", label: "Month" },
          ];
        `}
  </Preview.Data>
</Preview>
