All components
Forms
Toggle
stable
Since 1.1
On/off switch with three sizes, a slim treatment, label and description composition, and read-only and invalid states.
Forms
primitive
Form Control
Needs State Matrix
import { Toggle } from '@ivim/native/components';
When to use
Use when
A setting takes effect immediately, with no separate save step.
The choice is binary and reads naturally as on or off.
Don't use when
The choice is part of a form that is submitted later — use a Checkbox, which reads as "will be applied".
There are more than two states — use ButtonGroup or RadioGroup.
The user is agreeing to terms — a checkbox is the established consent control.
Playground
Adjust the controls to preview live prop combinations. The code snippet updates to match the current selection.
Weekly summary
size
size
sm
md
lg
Label placement
labelPlacement
end
start
Slim
slim
Invalid
isInvalid
Read only
isReadOnly
Disabled
isDisabled
Label
label
<Toggle label="Weekly summary" />
Example
Preview
Code
States
Off
On
With label and description
Weekly summary
Send a digest every Monday.
Label before the control
Compact mode
Invalid
Accept data processing
Required to continue.
Read only (still announced as enabled)
Two-factor authentication
Set by your administrator.
Disabled on
Disabled off
Sizes and treatments
Sizes (sm, md, lg)
Slim treatment
Migration note
`Switch` has been removed. It was a thin wrapper over React Native’s own switch with `value`/`onValueChange` and no accessible name, which left the family with two public controls and two vocabularies. `Toggle` is now the single control: replace `value` with `isSelected` and `onValueChange` with `onChange`.
Anatomy
The parts that compose this component.
1
Track
The rail, animating between the off and on colors.
2
Thumb
The knob, translating across the track.
3
Label
The setting name, and the accessible name. Can sit before or after the control.
4
Description
Supporting text beneath the label; takes the error color when invalid.
Guidelines
Do
Label the thing being switched, not the action ("Weekly summary", not "Enable weekly summary").
Do
Apply the change immediately; if it can fail, show the failure rather than silently reverting.
Do
Use isReadOnly for a setting fixed by policy, so it stays announced as an enabled, explicable control.
Don't
Pair a toggle with a Save button — that combination implies the change is pending, which contradicts the control.
Don't
Use a toggle when the two states are not opposites (for example "Card" versus "Bank transfer").
Props
Public props for this component. Required props are marked; defaults reflect the component implementation.
isSelected / defaultSelected
boolean
Controlled and uncontrolled on state.
onChange
(isSelected: boolean) => void
Fires with the next on state.
label / description
ReactNode
Setting name and supporting text.
labelPlacement
'start' | 'end'
default: 'end'
Whether the label sits before or after the control.
size
'sm' | 'md' | 'lg'
default: 'md'
Track, thumb, and label scale.
slim
boolean
default: false
Thin rail with an overhanging thumb, for dense settings lists. Presentational only.
isReadOnly
boolean
default: false
Blocks input but still announces as an enabled control.
isDisabled
boolean
default: false
Dims, blocks input, and announces disabled.
isInvalid
boolean
default: false
Applies the error treatment to the off track and description.
aria-label
string
Accessible name when there is no visible label, or when the label is not plain text.
Deviations from Untitled UI
Where this component deliberately differs from Untitled UI's API, and why. These are kept choices, not gaps to close.
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.
Accessibility
Roles and screen-reader behavior this component provides, plus keyboard interactions.
•
Announces accessibilityRole="switch" with checked state, updated immediately on press.
•
Takes its name from a string label, or from aria-label when there is no visible label.
•
Read-only rejects input but still announces as an enabled control, so a policy-fixed setting is explicable rather than merely unavailable.
•
Disabled announces as disabled and blocks input.
•
The slim treatment is purely presentational — semantics and behavior are unchanged.
Tab
Moves focus to the toggle.
Space / Enter
Flips the toggle.
Platform & RTL
Behavior that differs across the platforms this component runs on.
Web
Focusable with a visible inset focus ring matched to the pill radius.
iOS
VoiceOver announces the switch trait and its state; the thumb animates with the shared motion tokens.
Android
TalkBack announces the switch trait and its state.
RTL
Track travel and label placement mirror with the writing direction.
State coverage
Interaction and visual states this component supports.
default
focus
error
disabled
selected
Token references
Semantic design tokens this component page exercises. Tap one to edit it live.
Related components
Components that solve adjacent problems or compose with this one.
Checkbox
Independent on/off choice with indeterminate, invalid, and read-only states, plus a CheckboxGroup for related options.
RadioGroup
One-of-many choice as a list or as selectable cards, with icon, avatar, price, badge, and secondary-action slots.
ButtonGroup
Joined group of adjacent segments: an action group, or a single- or multiple-selection control with group and per-item disabled states.
Input
Single-line text entry, with TextField for labelled fields and InputGroup for adornments, prefixes, and attached controls.