---
name: aircall-blocks/migrate-dashboard/toggle-row
description: >
  Migrate @dashboard/library ToggleRow to @aircall/ds Field + Switch composition.
  Load when a file imports ToggleRow from @dashboard/library.
type: sub-skill
library: aircall-blocks
requires:
  - aircall-blocks/setup
  - aircall-blocks/migrate-dashboard
sources:
  - "aircall/hydra:packages/ds/src/index.ts"
---

This skill builds on aircall-blocks/migrate-dashboard.

## 1. Key premise

`ToggleRow` was a single component. The DS replacement is a **composition** of
`Field` (orientation="horizontal") + `Switch` + `FieldLabel` + optional `FieldDescription`.
There is no 1:1 component — you must assemble the parts.

## 2. Verified DS exports (`packages/ds/src/index.ts`)

```
Field, FieldLabel, FieldDescription, FieldTitle, FieldContent
Switch
Spinner
```

## 3. Imports

```tsx
import { Field, FieldDescription, FieldLabel, Spinner, Switch } from '@aircall/ds';
```

## 4. Prop mapping

| `ToggleRow` prop | DS equivalent |
| --- | --- |
| `label` | `<FieldLabel>` inside `<Field orientation="horizontal">` |
| `description` | `<FieldDescription>` next to `<FieldLabel>` |
| `value` | `<Switch checked={…}>` or `<Switch defaultChecked>` |
| `onChange` | `<Switch onCheckedChange={…}>` |
| `disabled` | `<Switch disabled>` |
| `loading` | Replace `<Switch>` with a `<Spinner>` in a `data-slot="switch"` wrapper (see §6) |
| `data-test` | Pass to `<Switch>` directly |

## 5. Structure

```tsx
<Field orientation="horizontal">
  <Switch />                          {/* or Spinner placeholder when loading */}
  <FieldLabel>Label text</FieldLabel>
</Field>
```

With description:
```tsx
<Field orientation="horizontal" className="max-w-sm">
  <Switch />
  <div className="flex flex-col gap-0.5">
    <FieldLabel>Label text</FieldLabel>
    <FieldDescription>Supporting description.</FieldDescription>
  </div>
</Field>
```

## 6. Before / After examples

### 6a. Label only

**Before:**
```tsx
import { ToggleRow } from '@dashboard/library';

<ToggleRow
  label="Enable notifications"
  value={enabled}
  onChange={setEnabled}
/>
```

**After:**
```tsx
import { Field, FieldLabel, Switch } from '@aircall/ds';

<Field orientation="horizontal">
  <Switch checked={enabled} onCheckedChange={setEnabled} />
  <FieldLabel>Enable notifications</FieldLabel>
</Field>
```

### 6b. With description

**Before:**
```tsx
<ToggleRow
  label="Recording"
  description="Automatically record all inbound calls."
  value={recording}
  onChange={setRecording}
/>
```

**After:**
```tsx
import { Field, FieldDescription, FieldLabel, Switch } from '@aircall/ds';

<Field orientation="horizontal" className="max-w-sm">
  <Switch checked={recording} onCheckedChange={setRecording} />
  <div className="flex flex-col gap-0.5">
    <FieldLabel>Recording</FieldLabel>
    <FieldDescription>Automatically record all inbound calls.</FieldDescription>
  </div>
</Field>
```

### 6c. Loading state

`ToggleRow` accepted a `loading` prop that replaced the toggle with a spinner.
In the DS, swap the `Switch` for a `Spinner` placed inside a `data-slot="switch"`
wrapper so Field's horizontal layout still aligns correctly:

**Before:**
```tsx
<ToggleRow label="Syncing contacts" loading={true} />
```

**After:**
```tsx
import { Field, FieldLabel, Spinner } from '@aircall/ds';

<Field orientation="horizontal">
  <div data-slot="switch" className="grid h-6 w-10 shrink-0 place-items-center">
    <Spinner size="default" />
  </div>
  <FieldLabel>Syncing contacts</FieldLabel>
</Field>
```

## 7. Common mistakes

### Mistake 1: Using `Switch` without `Field`

```tsx
// WRONG — no layout wrapper; label and switch won't align
<Switch checked={value} onCheckedChange={onChange} />
<label>Enable notifications</label>
```

```tsx
// CORRECT — Field orientation="horizontal" provides the flex row layout
<Field orientation="horizontal">
  <Switch checked={value} onCheckedChange={onChange} />
  <FieldLabel>Enable notifications</FieldLabel>
</Field>
```

### Mistake 2: Putting description inside FieldLabel

```tsx
// WRONG — FieldLabel is for the label text only
<FieldLabel>
  Recording
  <FieldDescription>…</FieldDescription>
</FieldLabel>
```

```tsx
// CORRECT — wrap label + description in a flex column div
<div className="flex flex-col gap-0.5">
  <FieldLabel>Recording</FieldLabel>
  <FieldDescription>…</FieldDescription>
</div>
```
