Switch
A switch button with role="switch".
Basic Usage
Basic usage
Disabled & Loading
disabled / loading
loading shows a loading animation and prevents toggling, for async submit scenarios.
Label
The label attribute renders a text label next to the switch; clicking the label toggles it (native label association) and provides the accessible name for role="switch". label-position="start" moves the label to the left (default end). Custom content can be placed in the default slot (takes precedence over the label attribute text).
Label
Hit-area note: the host shrinks to the actual control width (width: fit-content), so by default the visual width always matches the clickable area. When the host is explicitly stretched (e.g. align-stretch in a vertical oas-space, or width: 100%), clicking anywhere on the row toggles it — the iOS settings row semantics (the inner button and label areas still use their own channels, so no double toggling). Use label for a text hit target beside the switch. Without label, the host can set aria-label (mirrored onto the inner button as the accessible name).
Full-row click when stretched
disabled / loading states block the whole row just like the thumb.
Switch Labels
checked-text / unchecked-text render labels on the switch: at medium/large/xl sizes they appear inside the track on the side opposite the thumb; at size="xs" / size="small" the labels move outside the switch.
Switch labels
Sizes
size supports five tiers: xs / small / medium (default) / large / xl; invalid values fall back to medium with a warning.
Five sizes
Custom Color
color overrides the primary color of the checked state (defaults to --oas-color-primary).
Custom color
Thumb Icons
checked-icon / unchecked-icon render icons on the thumb (oas-icons names); the icon follows the on/off state — favorites, day/night mode and similar scenarios:
Thumb icons
Value Mapping
true-value / false-value customize the switch value (strings); detail.value of oas-change returns the mapped value (true / false booleans when unset). Reading el.value also returns the current mapped value — useful for form submissions like 'YES' / 'NO'.
true-value / false-value
Before Change
el.beforeChange = (next) => boolean | Promise<boolean> (JS property channel; attributes cannot carry functions): returning false or a rejected Promise cancels the toggle; while an async confirmation is in flight the component enters loading state (spinner + click blocked) to prevent duplicate triggers.
before-change async confirm
Validation Status
status="success" | "warning" | "error" tints the control (error also sets aria-invalid; a host-set aria-invalid gets the same error visuals):
status
Description
description renders a muted secondary line under the label explaining what the switch controls (same contract as the oas-checkbox / oas-radio description); rich content in slot[name="description"] wins over the attribute text:
Description
Card Variant (variant="card")
variant="card" upgrades the switch into a choice card: a bordered card wraps the thumb + label + description, the whole card is clickable (click anywhere on the card to toggle), and the selected state tints the border with the primary color over a faint background (same visual language as the oas-checkbox / oas-radio choice cards); disabled / status also apply to the card border. Ideal for settings-style per-item switch lists:
Card variant
Custom Width
--oas-switch-width / --oas-switch-height / --oas-switch-thumb-size CSS variables override the track width / height / thumb size across size tiers:
CSS variable sizing
Events
oas-change (detail: { checked, value }), oas-focus / oas-blur (focus enters / leaves the component).
Toggle events
Controlled usage: when the host owns the state, bind the checked attribute and write it back on oas-change (in Vue: :checked="x" + @oas-change="x = $event.detail.checked").
required
required (native validation chain)
required drives the native validation chain (form-associated): when unfilled, checkValidity() returns false (valueMissing) and native form submission is blocked; it recovers to :valid once filled.
API
oas-switch
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
aria-label | Accessible name (host override channel; explicit value wins over label derivation) | — | — |
checked | Whether on | boolean | — |
checked-icon | Checked-state thumb icon (oas-icon name) | string | — |
checked-text | Label shown when on; inside the track at medium/large/xl, outside at xs/small | — | — |
color | Custom primary color for the on state, overrides --oas-color-primary (CSS color value) | — | — |
description | Secondary description text (muted line under the label; slot[name=description] rich content wins over the attribute text), same contract as checkbox/radio description | string | — |
disabled | Disabled | boolean | — |
false-value | Mapped value when unchecked | string | — |
label | Label text (label channel; clicking the label toggles; same-named slot for rich content) | string | — |
label-position | Label position: end (default, right) / start (left) | string | — |
loading | Loading state, prevents toggling | boolean | — |
required | Required marker (drives the native valueMissing validation chain: off counts as unfilled) | boolean | — |
size | Size: xs / small / medium (default) / large / xl; invalid values fall back to medium with a warning | string | medium |
status | Validation status: error / warning / success; error mirrors aria-invalid | string | — |
true-value | Mapped value when checked (read via the value getter) | string | — |
unchecked-icon | Unchecked-state thumb icon | string | — |
unchecked-text | Label shown when off; inside the track at medium/large/xl, outside at xs/small | — | — |
variant | Variant: default (plain thumb) / card (a bordered card wrapping the thumb + label + description; whole card clickable, selected state tints the border, aligned with the checkbox/radio choice card); invalid values silently fall back to default | string | — |
Events
| Event | Description |
|---|---|
oas-blur | Fires on blur |
oas-change | Toggle, detail: { checked, value } (value is the mapped value) |
oas-focus | Fires on focus |
Slots
| Name | Description |
|---|---|
| default | Switch content (label / rich content) |
description | Rich description content (takes precedence over the description attribute text) |
CSS Variables
| CSS Variable | Description | Default |
|---|---|---|
--oas-glass-refraction | Liquid-glass edge refraction filter (active under data-glass, default none); for local opt-out override with an empty value (--oas-glass-refraction: ;)—not none (mixing none with button-state brightness() invalidates the whole filter declaration) | none |
--oas-switch-height | — | 22px |
--oas-switch-on-color | Label text color inside the on-track (when color overrides the track background, the component injects a dark/light text color by luminance; falls back to var(--oas-color-bg)) | var(--oas-color-bg) |
--oas-switch-thumb-size | — | 18px |
--oas-switch-width | — | 40px |