Switch
A toggle for an immediately-applied binary setting. A real checkbox under the hood, zero JS.
Last updated
Show codeHide code
<Switch label="Enable notifications" />
<Switch label="Auto-renew" checked />Add
npx @ava-ui/apogee add switch
No Apogee component dependencies. Zero JS.
Usage
---
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:
Show codeHide code
<Switch label="Default" checked />
<Switch variant="slim" label="Slim" checked />
<Switch variant="slim" label="Slim, off" />Sizes
Show codeHide code
<Switch size="small" label="Small" />
<Switch size="medium" label="Medium" />
<Switch size="large" label="Large" />Hint
Show codeHide code
<Switch label="Two-factor authentication" hint="A code from your authenticator app on every sign-in." />Reversed and slot label
Show codeHide code
<Switch reversed label="Email alerts" />
<Switch><span>Marketing <em>(optional)</em></span></Switch>States
Show codeHide code
<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 nativedisabledattribute. - RTL — the thumb translates the other direction under a
dir="rtl"ancestor.
Examples
No visible label — pass aria-label instead:
<Switch aria-label="Enable notifications" />
In a form, submitting a value when checked:
<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 —
Tabto focus,Spaceto toggle (native checkbox behavior). - No visible
label? Passaria-labeloraria-labelledbyvia 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
labeloraria-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.