KeepNeeds Refinement
Toggle Component link

A binary switch. 18 variants across State (Default / Pressed / Disabled) × Size (Large / Medium / Small) × isSelected (true / false). Vector track + thumb, all colors token-bound.

Rebuilt — normalized to the Selection Control schema
The rebuild added the Size axis (Large / Medium / Small), added interaction states, folded pressed into State (Default / Pressed / Disabled), and moved the booleans to lowercase true/false. Toggle now shares the same schema as Radio Button — State × Size × a selection boolean — and maps cleanly to native Toggle / Switch. Only Code Connect and the ARIA-role docs remain.
In Context

Toggle appears in settings rows, form opt-ins, and any control that flips a single boolean. Usually paired with a label (see Toggle - With Label).

Live Preview
Properties (today)
isActive
State
Proposed (post-normalization)
size
DS Health
Reusable
Pass
Generic on/off switch usable anywhere a boolean needs a visual control.
Self-contained
Pass
Owns its track, knob, colors, and shadow tokens.
Consistent
Pass
Normalized to the shared Selection Control schema — State (Default / Pressed / Disabled) × Size × isSelected (true/false), matching Radio Button. Pressed is folded into State rather than a stray boolean, and Disabled correctly omits Pressed. It now shares the full schema with Checkbox and Radio Button, including the isSelected boolean name.
Composable
Pass
Drops into rows and forms, and Toggle - With Label now nests it as a real instance — so atom changes propagate to the labeled variant.
Behavior
State iOS Android Figma Property Notes
Off / On Yes Yes isSelected=false / true Grey track + knob-left when off; brand #005CE5 track + knob-right when on.
Pressed Yes Yes State=Pressed Darker track for tap feedback. Composes with either isSelected. Derived at runtime on native, not a passed parameter.
Disabled Yes Yes State=Disabled Muted track/knob, tap blocked. Ships at both isSelected values; correctly has no Pressed pairing.
Focused N/A N/A N/A on mobile — touch has no focus ring.
Issues
  • ARIA role not documented. The native switch role and the required-toggle error announcement are not annotated on the component, so engineers have no spec for the a11y wiring. C7 · Code Connect Linkability
  • Code Connect mappings not registered. Schema is normalized and stable, so registration is unblocked — but the SwiftUI / Compose mappings are not yet wired and the native component does not exist. Snippets remain a Planned API. C7 · Code Connect Linkability
  • v2.0: Size axis added — Large / Medium / Small (48 / 40 / 32 wide), previously absent. (C2)
  • v2.0: Interaction states added — a State axis now covers Default / Pressed / Disabled where the old component had only on/off/disabled. (C5)
  • v2.1: Schema normalized to the Selection Control pattern — isPressed folded into State (Default / Pressed / Disabled, matching Radio Button), and the selection boolean moved from isActive=Yes/No to lowercase isActive=true/false. Disabled correctly omits Pressed. Same 18 variants, no illegal-combination gap. (C2)
  • v2.1: Divergence from the Checkbox / Radio Button schema closed on the structural axes — Toggle now shares State × Size × selection-boolean, so it maps to native Toggle / Switch the same way. (C2)
  • v2.2: Selection boolean renamed isActiveisSelected across all 18 variants — Toggle now uses the exact same name as Checkbox and Radio Button, so the three selection controls are fully interchangeable. (C2)
Recommendations
  • Document the ARIA / switch role. Spell out the native switch role and the required-toggle error announcement in the handoff spec. A11y
  • Register Code Connect mapping to EBToggle. Wire State, Size, and isSelected 1:1 to the SwiftUI Toggle / Compose Switch API. Docs
  • Normalize to the Selection Control schema. v2.1: Applied — State (Default / Pressed / Disabled) × Size × lowercase isSelected, matching Radio Button. Pressed folded into State; booleans lowercase. Property
  • Add the Size axis. v2.0: Applied — Large / Medium / Small. Property
  • Add interaction states. v2.0: Applied — Pressed and Disabled now ship as State values. State
  • Promote Toggle - With Label to a real component. v2.0: Applied — the labeled variant is now its own component that nests this Toggle as an instance (see the Toggle with Label assessment). Composition
  • Rename isActiveisSelected. v2.2: Applied — aligns the selection boolean with Checkbox and Radio Button across all 18 variants. Rename
States
Default · Off
DES DEV

The "off" resting state. Gray track, white knob pinned left.

Properties
isActive
State
Properties
State Default
isActive No
Colors
Track #C2CFE5
Indicator #FFFFFF
Layout
Track size 48 × 24
Knob size 20 × 20
Knob inset 2px
Corner radius 12px (pill)
Typography
N/A No text
Inactive — Colors

Off / unchecked state.

Role Token Default
Track toggle/color/default/inactive/bg-track #C2CFE5
Indicator toggle/color/default/inactive/bg-indicator #FFFFFF
Default · On
DES DEV

The "on" resting state. Brand-blue track, knob pinned right.

Properties
isActive
State
Properties
State Default
isActive Yes
Colors
Track #005CE5
Indicator #FFFFFF
Layout
Track size 48 × 24
Knob size 20 × 20
Knob inset 2px
Corner radius 12px (pill)
Typography
N/A No text
Active — Colors

On / checked state.

Role Token Default
Track toggle/color/default/active/bg-track #005CE5
Indicator toggle/color/default/active/bg-indicator #FFFFFF
Disabled · Off
DES DEV

Disabled off state. Muted gray track; interaction blocked.

Properties
isActive
State
Properties
State Disabled
isActive No
Colors
Track #EEF2F9
Indicator #F6F9FD
Layout
Track size 48 × 24
Knob size 20 × 20
Knob inset 2px
Corner radius 12px (pill)
Typography
N/A No text
Disabled Inactive — Colors

Disabled toggle in the off position — desaturated track.

Role Token Default
Track toggle/color/disabled/inactive/bg-track #E5EBF4
Indicator toggle/color/disabled/inactive/bg-indicator #F6F9FD
Disabled · On
DES DEV

Disabled on state. Muted brand-blue track; interaction blocked.

Properties
isActive
State
Properties
State Disabled
isActive Yes
Colors
Track #9BC5FD
Indicator #F6F9FD
Layout
Track size 48 × 24
Knob size 20 × 20
Knob inset 2px
Corner radius 12px (pill)
Typography
N/A No text
Disabled Active — Colors

Disabled toggle in the on position — muted brand fill.

Role Token Default
Track toggle/color/disabled/active/bg-track #9BC5FD
Indicator toggle/color/disabled/active/bg-indicator #F6F9FD
Property Mapping
Figma PropertySwiftUICompose
isActive: Yes | No isSelected: true | false @Binding var isOn: Bool
State: Default | Disabled State: Default | Pressed | Focused | Disabled | Error Modifier: .disabled(true), .ebState(.error)
(no size axis) Size: Small | Medium | Large .controlSize(.small / .regular / .large)
Accessibility
RequirementiOSAndroid
Switch role SwiftUI Toggle automatically applies the switch accessibility trait — VoiceOver says "on/off", not "checked/unchecked". Material Switch applies Role.Switch semantics automatically.
Touch target Minimum 44 × 44pt (pad the container — the 48×24 track alone is too small). Minimum 48 × 48dp.
State announcement VoiceOver announces "On" / "Off" as the value. TalkBack announces "On" / "Off" as the state description.
Disabled .disabled(true) blocks interaction; VoiceOver announces "dimmed". enabled = false blocks click; TalkBack announces "disabled".
Focus (external keyboard / switch control) iPad keyboards and Switch Control need a visible focus ring — must be added as part of the Focused state. D-pad / keyboard focus indicator — must be added as part of the Focused state.
Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready Track/knob layers cleanly named.
C2 Variant & Property Naming Requires Rework Rename isSelectedisSelected, values Yes/Notrue/false; add Size axis.
C3 Token Coverage Ready Track + knob + shadow bound to tokens.
C4 Native Mappability Ready Maps 1:1 to SwiftUI Toggle / Material Switch.
C5 Interaction State Coverage Requires Rework Missing Pressed, Focused, Error. Need full 5-state model.
C6 Asset & Icon Quality Not Applicable No icons.
C7 Code Connect Linkability Not Mapped Blocked until schema normalizes.
Variants Inventory (4 total)

State × isSelected = 4 variants today. Proposed: isSelected × State × Size = 30 variants.

#NodeStateisActiveDimensions
118482:36509DefaultNo48 × 24
218482:36512DefaultYes48 × 24
318482:36515DisabledNo48 × 24
418482:36518DisabledYes48 × 24
1.0.0 — April 2026Major
Initial Assessment · node 18482:36508
Verdict: Fix — Normalize to the shared Selection Control schema alongside Checkbox and Radio Button. Open
Schema
C2 — Property naming — Rename isSelectedisSelected; change values Yes/Notrue/false. Open
C2
C5 — States — Add Pressed, Focused, Error states. Add Small/Medium/Large size axis. Open
C5
C7 — Code Connect — Blocked until schema normalizes. Open
C7