

<Preview name="SwitchStatesExample" />

## Overview [#overview]

The `Switch` component provides a toggle control for binary choices. The track
lands two surface levels above its parent, unchecked hover follows the shared
surface hover system, and the thumb resets to `surface-1` while keeping its
border two levels above the track.

## Usage [#usage]

```tsx
import { Label } from "@tilt-legal/cubitt-components/label";
import { Switch } from "@tilt-legal/cubitt-components/switch";
```

```tsx
<Switch />
```

Always associate switches with descriptive labels for better accessibility and
to make label hover trigger the same interaction state as the switch.

```tsx
<Label orientation="horizontal">
  <Switch />
  Enable notifications
</Label>
```

## URL State [#url-state]

Provide `paramName` to sync the switch state with the current URL.

```tsx
<Label orientation="horizontal">
  <Switch defaultChecked={false} paramName="notifications" />
  Enable notifications
</Label>
```

## Examples [#examples]

### States [#states]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="SwitchStatesExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { useState } from "react";
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";
    import {
      ToggleGroup,
      ToggleGroupItem,
    } from "@tilt-legal/cubitt-components/toggle-group";

    type SwitchState = "off" | "on" | "disabled" | "invalid";

    const states = ["off", "on", "disabled", "invalid"] as const;
    const [state, setState] = useState<SwitchState>("off");
    const checked = state === "on";

    <>
      <Label orientation="horizontal">
        <Switch
          aria-invalid={state === "invalid" ? true : undefined}
          checked={checked}
          disabled={state === "disabled"}
          onCheckedChange={(nextChecked) => {
            setState(nextChecked ? "on" : "off");
          }}
        />
        {state}
      </Label>
      <PreviewFooter>
        <ToggleGroup
          aria-label="Switch state"
          groupVariant="segmented"
          multiple={false}
          onValueChange={(value) => {
            if (states.includes(value as SwitchState)) {
              setState(value as SwitchState);
            }
          }}
          value={state}
        >
          <ToggleGroupItem value="off">Off</ToggleGroupItem>
          <ToggleGroupItem value="on">On</ToggleGroupItem>
          <ToggleGroupItem value="disabled">Disabled</ToggleGroupItem>
          <ToggleGroupItem value="invalid">Invalid</ToggleGroupItem>
        </ToggleGroup>
      </PreviewFooter>
    </>;
    ```
  </Tab>
</Tabs>

### Default [#default]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="BasicSwitchExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";

    export default function Component() {
      return (
        <Label orientation="horizontal">
          <Switch />
          Default switch
        </Label>
      );
    }
    ```
  </Tab>
</Tabs>

### Sizes [#sizes]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="SwitchSizesExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";

    export default function Component() {
      return (
        <div className="flex items-center gap-6">
          <Label orientation="horizontal">
            <Switch size="sm" />
            Small
          </Label>
          <Label orientation="horizontal">
            <Switch size="md" />
            Medium
          </Label>
          <Label orientation="horizontal">
            <Switch size="lg" />
            Large
          </Label>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### Checked by Default [#checked-by-default]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="CheckedByDefaultExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";

    export default function Component() {
      return (
        <Label orientation="horizontal">
          <Switch defaultChecked />
          Enabled by default
        </Label>
      );
    }
    ```
  </Tab>
</Tabs>

### Disabled [#disabled]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="DisabledSwitchExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";

    export default function Component() {
      return (
        <div className="flex flex-col gap-4">
          <Label orientation="horizontal">
            <Switch disabled />
            Disabled (off)
          </Label>
          <Label orientation="horizontal">
            <Switch disabled defaultChecked />
            Disabled (on)
          </Label>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### With Description [#with-description]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="WithDescriptionExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";

    export default function Component() {
      return (
        <Label orientation="horizontal" className="items-start gap-3">
          <Switch />
          <div className="grid gap-1.5">
            <span className="font-medium">Marketing emails</span>
            <p className="text-fg-2 text-sm">
              Receive emails about new products, features, and more.
            </p>
          </div>
        </Label>
      );
    }
    ```
  </Tab>
</Tabs>

### Settings Card [#settings-card]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="SettingsCardExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Card, CardContent } from "@tilt-legal/cubitt-components/card";
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";

    export default function Component() {
      return (
        <Label className="block" orientation="horizontal">
          <Card className="w-full max-w-sm" hoverable>
            <CardContent className="flex-row items-start gap-3 p-4!">
              <Switch id="switch-1" size="sm" />
              <div className="grid gap-1.5 font-normal">
                <p className="font-medium text-sm leading-none">
                  Enable notifications
                </p>
                <p className="text-fg-2 text-sm">
                  You can enable or disable notifications at any time.
                </p>
              </div>
            </CardContent>
          </Card>
        </Label>
      );
    }
    ```
  </Tab>
</Tabs>

### URL State [#url-state-1]

Sync a switch state with the URL. Try toggling the switch and refreshing the page or sharing the URL.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="SwitchURLStateExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Label } from "@tilt-legal/cubitt-components/label";
    import { Switch } from "@tilt-legal/cubitt-components/switch";

    export default function Component() {
      return (
        <Label orientation="horizontal">
          <Switch paramName="demo-notifications" defaultChecked={false} />
          Enable notifications
        </Label>
      );
    }
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### Switch [#switch]

The root component for creating switches with multiple size variants.

| Prop              | Type                                                                                | Default           | Description                                       |
| ----------------- | ----------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------- |
| `checked`         | `boolean`                                                                           | -                 | Controlled checked state.                         |
| `defaultChecked`  | `boolean`                                                                           | `false`           | Initial checked state when uncontrolled.          |
| `onCheckedChange` | `(checked: boolean, eventDetails: SwitchPrimitive.Root.ChangeEventDetails) => void` | -                 | Called when the checked state changes.            |
| `size`            | `"sm" \| "md" \| "lg"`                                                              | `"md"`            | Switch size.                                      |
| `disabled`        | `boolean`                                                                           | `false`           | Disables the switch.                              |
| `required`        | `boolean`                                                                           | `false`           | Marks the switch as required for form submission. |
| `name`            | `string`                                                                            | -                 | Form field name.                                  |
| `value`           | `string`                                                                            | `"on"`            | Form value when checked.                          |
| `id`              | `string`                                                                            | -                 | HTML id for explicit label association.           |
| `className`       | `string`                                                                            | -                 | Additional classes for the switch root.           |
| `children`        | `React.ReactNode`                                                                   | `<SwitchThumb />` | Custom thumb content.                             |

#### URL State Props [#url-state-props]

When provided with a `paramName`, the switch will sync its state with URL parameters via TanStack Router search params.

| Prop                  | Type                                 | Default | Description                                              |
| --------------------- | ------------------------------------ | ------- | -------------------------------------------------------- |
| `paramName`           | `string`                             | -       | URL parameter name for syncing state.                    |
| `paramValue`          | `boolean`                            | -       | Controlled URL state value.                              |
| `onUrlValueChange`    | `(checked: boolean \| null) => void` | -       | Called when the URL value changes.                       |
| `paramClearOnDefault` | `boolean`                            | `true`  | Removes the URL parameter when value equals the default. |
| `paramDebounce`       | `number`                             | -       | Debounce window for URL updates.                         |
| `paramThrottle`       | `number`                             | -       | Throttle window for URL updates.                         |

### SwitchThumb [#switchthumb]

The thumb component that slides within the switch track.

| Prop        | Type                       | Default | Description                           |
| ----------- | -------------------------- | ------- | ------------------------------------- |
| `size`      | `"sm"` \| `"md"` \| `"lg"` | —       | Override the size from parent Switch. |
| `className` | `string`                   | —       | Additional CSS classes for the thumb. |
