# Switch

> A toggle for an immediately-applied binary setting. A real checkbox under the hood, zero JS.

URL: https://apogee.avaui.dev/docs/switch
Last updated: 2026-10-15

A toggle for an immediately-applied binary setting. A real checkbox under the hood, zero JS.

Last updated October 15, 2026

```astro
<Switch label="Enable notifications" />
<Switch label="Auto-renew" checked />
```

## Add

```sh
npx @ava-ui/apogee add switch
```

No Apogee component dependencies. Zero JS.

## Usage

```astro
---
import Switch from '@/components/apogee/Switch/Switch.astro'
---
<Switch id="notifications" name="notifications" label="Enable notifications" />
```

## API

`@composable` — exposed to Content Editors in AVA. The `Props` interface is an open index signature (`[key: string]: any`), so any native `<input>` attribute not listed below (`checked`, `disabled`, `name`, `value`, `required`, `aria-label`, …) passes through to the underlying checkbox.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` | auto-generated (`apogee-<random>`) | Connects the `<label>` to the `<input>`. Set your own to target it from elsewhere (a separate `<label for>`, a test selector). |
| `label` | `string` | — | Visible label text, rendered after the track. |
| `size` | `'small' \| 'medium' \| 'large'` | `'medium'` | Track and label size. |
| `reversed` | `boolean` | `false` | Label first, switch last. |
| `variant` | `'default' \| 'slim'` | `'default'` | `slim`: a thin faded track with a bordered knob that overhangs it. |
| `hasError` | `boolean` | `false` | Marks the switch invalid: `aria-invalid` on the input, a critical ring on the track. |
| `hint` | `string` | — | Supporting text under the label; the input lists it in `aria-describedby`. The label turns medium weight to read as a heading. |
| `class` | `string` | — | Extra classes on the root `<label>`, appended last. |
| …rest | — | — | Any other attribute passes through to the `<input type="checkbox" role="switch">`. |

## Variants

Every `variant`:

```astro
<Switch label="Default" checked />
<Switch variant="slim" label="Slim" checked />
<Switch variant="slim" label="Slim, off" />
```

## Sizes

```astro
<Switch size="small" label="Small" />
<Switch size="medium" label="Medium" />
<Switch size="large" label="Large" />
```

## Hint

```astro
<Switch label="Two-factor authentication" hint="A code from your authenticator app on every sign-in." />
```

## Reversed and slot label

```astro
<Switch reversed label="Email alerts" />
<Switch><span>Marketing <em>(optional)</em></span></Switch>
```

## States

```astro
<Switch label="Off" />
<Switch label="On" checked />
<Switch label="Disabled" disabled />
<Switch label="Disabled, on" checked disabled />
```

-   **Unchecked / checked** — the track fill and thumb position flip on `peer-checked`.
-   **Focus** — a visible ring on the track when the hidden input has keyboard focus (`peer-focus-visible:outline`).
-   **Disabled** — the track takes the disabled fill (`peer-disabled:bg-disabled`); pass the native `disabled` attribute.
-   **RTL** — the thumb translates the other direction under a `dir="rtl"` ancestor.

## Examples

No visible label — pass `aria-label` instead:

```astro
<Switch aria-label="Enable notifications" />
```

In a form, submitting a value when checked:

```astro
<Switch name="notifications" value="on" label="Enable notifications" />
```

## Accessibility

-   A real `<input type="checkbox" role="switch">`, visually hidden (`sr-only`) but present in the tab order — full keyboard and AT support for free.
-   The `<label for>` wraps the whole control, so clicking the track or the label text both toggle it.
-   **Keyboard** — `Tab` to focus, `Space` to toggle (native checkbox behavior).
-   No visible `label`? Pass `aria-label` or `aria-labelledby` via passthrough — without one the switch has no accessible name.
-   Zero JS — no no-JS fallback to note.

## Tokens

| Token | Used for |
| --- | --- |
| `--background-neutral` | Track background (unchecked) |
| `--background-disabled` | Track background (disabled) |
| `--background-primary` | Track background (checked) |
| `--outline-color-focus` | Focus ring |

## Do / Don’t

-   **Do** use Switch for a setting that applies immediately (e.g. “Auto-renew”).
-   **Do** pass a `label` or `aria-label` — never ship a switch with no accessible name.
-   **Don’t** use Switch for an action that needs a confirm step — that’s a `Button`.
-   **Don’t** pair a Switch with a separate “Save” button for that one setting — if it applies instantly, say so in nearby copy instead.

## Content

-   Label states the setting being turned on, not the action (“Auto-renew”, not “Toggle auto-renew”).
-   Sentence case, no ending punctuation.

## Related

[

CheckboxA native checkbox with a custom look. Toggle a single option, or one item in a multi-select list.

](https://apogee.avaui.dev/docs/checkbox)[

IconToggleTwo icons in one box that swap with a scale and fade, driven by a ToggleButton or your own state.

](https://apogee.avaui.dev/docs/icon-toggle)[

ToggleButtonA two-state button (aria-pressed) — icon and/or text, on or off.

](https://apogee.avaui.dev/docs/toggle-button)
