# Switch

> Toggle input for binary settings with on/off states and smooth transitions.

- Available in: `@sisyphos-ui/react`, `@sisyphos-ui/vue`, `@sisyphos-ui/angular`
- Docs: https://www.sisyphosui.com/docs/components/switch
- WAI-ARIA pattern: [Switch](https://www.w3.org/WAI/ARIA/apg/patterns/switch/)

## Installation

Pick the framework binding that matches your stack:

```bash
pnpm add @sisyphos-ui/react   # React 18+
pnpm add @sisyphos-ui/vue     # Vue 3+
pnpm add @sisyphos-ui/angular # Angular 17+
```

## Import

```tsx
import "@sisyphos-ui/react/styles.css";
import { Switch } from "@sisyphos-ui/react";
```

## Framework usage

### React 18+

```tsx
import { useState } from "react";
import { Switch } from "@sisyphos-ui/react";

export const Notifications = () => {
  const [on, setOn] = useState(true);
  return <Switch checked={on} onChange={setOn} aria-label="Notifications" />;
};
```

### Vue 3+

```vue
<script setup lang="ts">
import { ref } from "vue";
import { Switch } from "@sisyphos-ui/vue";
const on = ref(true);
</script>

<template>
  <Switch v-model:checked="on" aria-label="Notifications" />
</template>
```

### Angular 17+

```ts
import { Component, signal } from "@angular/core";
import { Switch } from "@sisyphos-ui/angular";

@Component({
  selector: "app-notifications",
  standalone: true,
  imports: [Switch],
  template: `<sui-switch [(checked)]="on" ariaLabel="Notifications" />`,
})
export class NotificationsComponent {
  on = signal(true);
}
```

## Examples

### Default

Switch has `role="switch"` and requires an accessible label.

```tsx
import { useState } from "react";
import { Switch } from "@sisyphos-ui/react";

export function Example() {
  const [on, setOn] = useState(true);
  const [autoSave, setAutoSave] = useState(false);

  return (
    <div className="flex flex-col gap-3">
      <label className="flex items-center gap-3 text-sm">
        <Switch checked={on} onChange={setOn} aria-label="Notifications" />
        Enable notifications
      </label>
      <label className="flex items-center gap-3 text-sm">
        <Switch checked={autoSave} onChange={setAutoSave} aria-label="Auto-save" color="success" />
        Auto-save
      </label>
      <label className="flex items-center gap-3 text-sm opacity-60">
        <Switch checked disabled aria-label="Pro features" />
        Pro features (disabled)
      </label>
    </div>
  );
}
```

### Sizes

`sm`/`md`/`lg` control the track and thumb dimensions.

```tsx
import { useState } from "react";
import { Switch } from "@sisyphos-ui/react";

export function Example() {
  const [vals, setVals] = useState({ sm: true, md: true, lg: true });

  return (
    <>
      <Switch size="sm" checked={vals.sm} onChange={(c) => setVals(v => ({ ...v, sm: c }))} aria-label="Small" />
      <Switch size="md" checked={vals.md} onChange={(c) => setVals(v => ({ ...v, md: c }))} aria-label="Medium" />
      <Switch size="lg" checked={vals.lg} onChange={(c) => setVals(v => ({ ...v, lg: c }))} aria-label="Large" />
    </>
  );
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| **checked** (required) | `boolean` | — | Current checked state. Always controlled. |
| onChange | `(checked: boolean) => void` | — | Called with the new checked value when the user toggles the switch. |
| color | `"neutral" \| "primary" \| "success" \| "error" \| "warning" \| "info"` | `"primary"` | Semantic color used when checked. |
| size | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | Switch dimensions. |
| disabled | `boolean` | `false` | Disables interaction and applies the disabled visual. |
| aria-label | `string` | — | Accessible name; required when no visible label is rendered alongside the switch. |

## Keyboard interactions

- **Space** — Toggles the switch.
- **Enter** — Toggles the switch.
- **Tab** — Moves focus to the next focusable element.

## Accessibility notes

- Renders as a native `<button>` with `role="switch"`; `aria-checked` reflects `checked`.
- `aria-disabled` mirrors `disabled`, and the switch is removed from the tab order (`tabIndex={-1}`) while disabled.
- `aria-label` is required when no adjacent visible label exists.
- The visual toggle thumb is `aria-hidden` so only the switch state is announced.

<!-- exports: { "Switch": "@sisyphos-ui/react" } -->