---
title: Toggle Group
description: A set of toggle buttons supporting single or multiple selection.
---

<PackageInfo name="toggle-group" />

**bun**

```bash
bun add @data-slot/toggle-group
```

**npm**

```bash
npm install @data-slot/toggle-group
```

**pnpm**

```bash
pnpm add @data-slot/toggle-group
```

## Anatomy

Each item needs a `data-value`. Add `data-multiple` for a group where several buttons can be pressed at once.

```html
<!-- Single selection (default) -->
<div data-slot="toggle-group" data-default-value="center">
  <button data-slot="toggle-group-item" data-value="left">Left</button>
  <button data-slot="toggle-group-item" data-value="center">Center</button>
  <button data-slot="toggle-group-item" data-value="right">Right</button>
</div>

<!-- Multiple selection -->
<div data-slot="toggle-group" data-multiple data-default-value="bold italic">
  <button data-slot="toggle-group-item" data-value="bold">B</button>
  <button data-slot="toggle-group-item" data-value="italic">I</button>
  <button data-slot="toggle-group-item" data-value="underline">U</button>
</div>
```

## Examples

### Pick one of several

<Example name="toggle-group" />

### Disabled state

`data-disabled` on the root disables every button in the group.

<Example name="toggle-group" variant="extra" />

## API reference

### Initialization

#### `create(scope?)`

Find and bind uninitialized `[data-slot="toggle-group"]` descendants of `scope` (defaults to `document`). Returns `ToggleGroupController[]` for newly bound roots. To initialize the scope element itself, use `createToggleGroup`.

```typescript
import { create } from "@data-slot/toggle-group";

const controllers = create();
```

#### `createToggleGroup(root, options?)`

Create a `ToggleGroupController` for one root element. JavaScript options take precedence over the corresponding data attributes. Calling this again for a bound root returns its existing controller; destroy it before rebinding with new options.

```typescript
import { createToggleGroup } from "@data-slot/toggle-group";

const controller = createToggleGroup(element, {});
```

### Slots

#### Runtime Slots

- `toggle-group` - Root element that manages single or multiple selection and keyboard navigation between items.
- `toggle-group-item` - Toggle button inside the group, identified by a unique `data-value`; receives `aria-pressed` and `data-state` as its selection changes.

### Data Attributes

#### Root Element

| Attribute | Description |
|-----------|-------------|
| `data-slot="toggle-group"` | Required. Identifies the root element. |
| `data-default-value` | Initial selected value(s). Space-separated for multiple values. |
| `data-multiple` | Enable multiple selection mode. |
| `data-orientation` | `"horizontal"` or `"vertical"` for keyboard navigation. |
| `data-loop` | Wrap keyboard focus at the ends (default `true`); use `"false"` to stop at the ends. |
| `data-disabled` | Disable the entire group. |

#### Item Elements

| Attribute | Description |
|-----------|-------------|
| `data-slot="toggle-group-item"` | Required. Identifies an item. |
| `data-value` | Required. The value associated with this item. |
| `data-disabled` | Disable this specific item. |

#### State Attributes (set by component)

| Attribute | Values | Description |
|-----------|--------|-------------|
| `aria-pressed` | `"true"` \| `"false"` | Whether item is pressed. |
| `data-state` | `"on"` \| `"off"` | Visual state for styling. |
| `data-value` (on root) | Space-separated values | Current selection. |

### Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `defaultValue` | `string \| string[]` | `[]` | Initial selected value(s). For multiple values, use array or space-separated string. |
| `multiple` | `boolean` | `false` | Allow multiple selections. |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Orientation for keyboard navigation. |
| `loop` | `boolean` | `true` | Wrap keyboard focus at ends. |
| `disabled` | `boolean` | `false` | Disable the entire group. |
| `onValueChange` | `(value: string[]) => void` | - | Callback when selection changes. |

### Controller

| Method/Property | Description |
| --- | --- |
| `setValue(value: string \| string[])` | Replace the selection. Strings are space-separated; unknown values are ignored and single mode keeps the first matching value. |
| `toggle(value: string)` | Toggle one value; single mode clears the previous selection. |
| `value` | Current selection (readonly `string[]`, including in single mode). |
| `destroy()` | Remove listeners and release the root binding. |

Controller methods work while the group is disabled. User interaction and `toggle-group:set` are blocked while disabled.

### Events

#### Outbound Events

```javascript
// Listen for changes
root.addEventListener("toggle-group:change", (e) => {
  console.log(e.detail.value); // string[]
});
```

#### Inbound Events

| Event | Detail | Description |
|-------|--------|-------------|
| `toggle-group:set` | `{ value: string \| string[] }` | Set selection programmatically |

```javascript
// Set selection from outside
root.dispatchEvent(new CustomEvent("toggle-group:set", {
  detail: { value: "bold" }
}));

// Set multiple values
root.dispatchEvent(new CustomEvent("toggle-group:set", {
  detail: { value: ["bold", "italic"] }
}));
```

**Note:** Blocked when group is disabled.

#### Deprecated Shapes

The following shapes are deprecated and will be removed in v1.0:

```javascript
// Deprecated: bare string
root.dispatchEvent(new CustomEvent("toggle-group:set", {
  detail: "bold"
}));

// Deprecated: bare array
root.dispatchEvent(new CustomEvent("toggle-group:set", {
  detail: ["bold", "italic"]
}));
```

Use `{ value: ... }` instead.

### Styling

```css
/* Style pressed items */
[data-slot="toggle-group-item"][data-state="on"] {
  background: #333;
  color: white;
}

/* Style disabled items */
[data-slot="toggle-group-item"][aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}
```

### Keyboard Navigation

| Key | Action |
|-----|--------|
| `ArrowRight` / `ArrowDown` | Move to next item (based on orientation) |
| `ArrowLeft` / `ArrowUp` | Move to previous item (based on orientation) |
| `Home` | Move to first item |
| `End` | Move to last item |
| `Enter` / `Space` | Toggle current item |

### Accessibility

- Root has `role="group"`
- Items have `aria-pressed` attribute
- Disabled items have `aria-disabled="true"` and native `disabled`
- Supports roving tabindex for keyboard navigation
- Add `aria-label` or `aria-labelledby` to root for context
