# ToggleGroup

> A segmented row of toggle buttons with roving-tabindex keyboard navigation and single or multiple selection.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: Actions
- Tags: toggle, segmented-control, roving-tabindex, compound, selection, toolbar
- Docs: https://fancy-ui.rama.app/docs/components/toggle-group
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/toggle-group

## Import

```svelte
<script lang="ts">
  import { ToggleGroup } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { ToggleGroup } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `"single" \| "multiple"` | `"single"` | Whether one item can be active at a time, or several. |
| `value` | `string \| string[]` | `""` | The active value(s), bindable — a string when type="single", an array of strings when type="multiple". |
| `onValueChange` | `(value: string \| string[]) => void` | — | Called with the new value, shaped to match `type`, whenever the selection changes. |
| `disabled` | `boolean` | `false` | Disables every item in the group. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Sizes every item. |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | The rail's stacking axis; both arrow-key pairs work either way. |
| `label` | `string` | — | Accessible name for the group. |
| `class` | `string` | — | Additional CSS classes, merged onto the root. |
| `ref` | `HTMLDivElement \| null` | `null` | Bindable reference to the root element. |
| `sound` | `boolean` | `false` | Plays toggle-on/toggle-off on a multi-select item or select on a single-select change, once the user has enabled sound |
| `ToggleGroupItem.value` (required) | `string` | — | The item's value — what gets added to or removed from the group's selection. |
| `ToggleGroupItem.disabled` | `boolean` | `false` | Disables just this item, independent of the group's own `disabled`. |
| `ToggleGroupItem.label` | `string` | — | Accessible name for icon-only content on this item. Also the text fallback. |
| `ToggleGroupItem.class` | `string` | — | Additional CSS classes, merged onto the item's button. |
| `ToggleGroupItem.ref` | `HTMLButtonElement \| null` | `null` | Bindable reference to the item's button element. |

## Snippets

| Snippet | Description |
| --- | --- |
| `children` | The ToggleGroup's content — the ToggleGroupItems. |
| `ToggleGroupItem.children` | The item's content, typically a glyph or a short label. |

## Examples

### Basic Usage

```svelte
<script lang="ts">
	import { ToggleGroup, ToggleGroupItem } from "fancy-ui-svelte";

	let alignment = $state("left");
</script>

<ToggleGroup sound bind:value={alignment} label="Text alignment">
	<ToggleGroupItem value="left" label="Align left">
		<svg
			class="size-4"
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			stroke-width="2"
			stroke-linecap="round"
			aria-hidden="true"
		>
			<line x1="3" y1="6" x2="21" y2="6" />
			<line x1="3" y1="12" x2="15" y2="12" />
			<line x1="3" y1="18" x2="18" y2="18" />
		</svg>
	</ToggleGroupItem>
	<ToggleGroupItem value="center" label="Align center">
		<svg
			class="size-4"
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			stroke-width="2"
			stroke-linecap="round"
			aria-hidden="true"
		>
			<line x1="3" y1="6" x2="21" y2="6" />
			<line x1="6" y1="12" x2="18" y2="12" />
			<line x1="4" y1="18" x2="20" y2="18" />
		</svg>
	</ToggleGroupItem>
	<ToggleGroupItem value="right" label="Align right">
		<svg
			class="size-4"
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			stroke-width="2"
			stroke-linecap="round"
			aria-hidden="true"
		>
			<line x1="3" y1="6" x2="21" y2="6" />
			<line x1="9" y1="12" x2="21" y2="12" />
			<line x1="6" y1="18" x2="21" y2="18" />
		</svg>
	</ToggleGroupItem>
</ToggleGroup>
```

### Single Selection

Activating the active item again clears it.

```svelte
<script lang="ts">
	import { ToggleGroup, ToggleGroupItem } from "fancy-ui-svelte";

	let view = $state("day");
</script>

<div class="flex flex-col items-start gap-2">
	<ToggleGroup sound bind:value={view} label="Calendar view">
		<ToggleGroupItem value="day">Day</ToggleGroupItem>
		<ToggleGroupItem value="week">Week</ToggleGroupItem>
		<ToggleGroupItem value="month">Month</ToggleGroupItem>
	</ToggleGroup>

	<!-- Activating the active item again clears it — the one state a native
	     radio group cannot express. -->
	<p class="text-muted-foreground text-sm">
		{view === ""
			? "No view selected — click one, then click it again to clear it."
			: `Showing the ${view} view.`}
	</p>
</div>
```

### Multiple Selection

Independent on/off marks with type="multiple".

```svelte
<script lang="ts">
	import { ToggleGroup, ToggleGroupItem } from "fancy-ui-svelte";

	let marks = $state<string[]>(["bold"]);
</script>

<div class="flex flex-col gap-3">
	<ToggleGroup sound type="multiple" bind:value={marks} label="Formatting">
		<ToggleGroupItem value="bold" label="Bold"><strong>B</strong></ToggleGroupItem>
		<ToggleGroupItem value="italic" label="Italic"><em>I</em></ToggleGroupItem>
		<ToggleGroupItem value="underline" label="Underline">
			<span class="underline">U</span>
		</ToggleGroupItem>
	</ToggleGroup>

	<p
		class="text-sm"
		class:font-bold={marks.includes("bold")}
		class:italic={marks.includes("italic")}
		class:underline={marks.includes("underline")}
	>
		Toggle the marks above to preview how this sentence would look.
	</p>
</div>
```

### Vertical

A vertical rail — both arrow-key pairs still work.

```svelte
<script lang="ts">
	import { ToggleGroup, ToggleGroupItem } from "fancy-ui-svelte";

	let tool = $state("select");
</script>

<ToggleGroup sound bind:value={tool} orientation="vertical" label="Tool">
	<ToggleGroupItem value="select" label="Select">
		<svg
			class="size-4"
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			stroke-width="2"
			stroke-linecap="round"
			stroke-linejoin="round"
			aria-hidden="true"
		>
			<path d="m3 3 7.07 16.97 2.51-7.39 7.39-2.51L3 3z" />
		</svg>
	</ToggleGroupItem>
	<ToggleGroupItem value="pan" label="Pan">
		<svg
			class="size-4"
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			stroke-width="2"
			stroke-linecap="round"
			stroke-linejoin="round"
			aria-hidden="true"
		>
			<path d="M18 11V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v0" />
			<path d="M14 10V4a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v2" />
			<path d="M10 10.5V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v8" />
			<path
				d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15"
			/>
		</svg>
	</ToggleGroupItem>
	<ToggleGroupItem value="zoom" label="Zoom">
		<svg
			class="size-4"
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			stroke-width="2"
			stroke-linecap="round"
			stroke-linejoin="round"
			aria-hidden="true"
		>
			<circle cx="11" cy="11" r="8" />
			<line x1="21" y1="21" x2="16.65" y2="16.65" />
		</svg>
	</ToggleGroupItem>
</ToggleGroup>
```

### Disabled Items

One item unavailable; the keyboard model skips it.

```svelte
<script lang="ts">
	import { ToggleGroup, ToggleGroupItem } from "fancy-ui-svelte";

	let plan = $state("starter");
</script>

<div class="flex flex-col items-start gap-2">
	<ToggleGroup sound bind:value={plan} label="Plan">
		<ToggleGroupItem value="starter">Starter</ToggleGroupItem>
		<ToggleGroupItem value="team" disabled>Team</ToggleGroupItem>
		<ToggleGroupItem value="enterprise">Enterprise</ToggleGroupItem>
	</ToggleGroup>
	<p class="text-muted-foreground text-sm">
		"Team" is unavailable on this account — the arrow keys and Home/End step around it, and it can
		never end up focused or selected.
	</p>
</div>
```
