Skip to main content
iOS / SwiftUI · WCAG 2.2 AA

Switch

Native SwiftUI Toggle representing a persistent on/off setting. The label and switch state merge into a single accessible element.

Selection

The criteria an agent checks before retrieving this component.

Use when

  • Use when a control represents a persistent binary setting that remains on or off beyond the current interaction (e.g., "Enable notifications", "Dark mode"). Uses a native SwiftUI Toggle, whose label and switch state merge into a single accessible element.
  • Use when the setting takes effect immediately when toggled, without requiring form submission.
  • Use when the control reflects the current state of a system or application preference.

Try a different component when

  • Do not use when the control triggers an in-place action or transient feature toggle within the current context (use button.toggle).
  • Do not use when more than two states are required, or the state cycles through several values (use button.toggle).

Must Haves

Non-negotiable structure. Every generated instance must satisfy these rules.

  • Use the native Toggle control rather than a custom composition, and pass the label directly into the initializer (e.g., Toggle("Enable notifications", isOn: $binding)) so the label, switch role, and on/off state merge into a single accessible element.
  • The switch has an accessible name that describes the setting. Often this is worded to be true when the switch is on (e.g., "Enable notifications").
  • When there is no unique visible label (e.g., repeated switches in a list sharing generic visual text), give each Toggle a unique, specific .accessibilityLabel.
  • When the on/off state is represented by visible value text other than "On"/"Off" (e.g., "Allowed"/"Blocked", "Dark"/"Light"), set .accessibilityValue to match so VoiceOver announces the correct state instead of defaulting to generic On/Off wording.
  • The off-state fill maintains at least 3:1 contrast against the adjacent background, so the off state is distinguishable by more than color (a plain light gray is a common offender).
  • Meets the touch target size baseline in global_rules.md (global.touch-target-size).
  • Meets the system focus indicator baseline in global_rules.md (global.focus-visible).

Donts

Avoid these accessibility and UX barriers.

  • Do not build a switch out of a custom HStack of Text plus a shape-based knob without grouping it. Without an explicit Toggle (or .accessibilityElement(children: .combine)), the label and the control become two disconnected accessibility elements instead of one combined name-and-state announcement.
  • Do not leave .accessibilityValue mismatched with the visible value text when the switch shows custom state wording instead of On/Off.
  • Do not rely on color alone (e.g., green vs. gray) to convey on/off state; the off state must remain distinguishable through sufficient contrast.

Customizable

Alternatives and options that give the AI agent some room to move.

  • A custom .toggleStyle may restyle appearance (color, shape, knob position) as long as it continues to wrap a real Toggle underneath, preserving native semantics rather than rebuilding the control from scratch.

Golden Pattern

The tested reference implementation. Agents start from this shape and adapt to the developer’s codebase and context.

SWIFT
import SwiftUI

struct SwitchBasicDemo: View {
@State private var notifications = false
@State private var displayMode = false

var body: some View {
VStack(alignment: .leading, spacing: 16) {
// Native Toggle: label, switch, and state merge into one accessible element
Toggle("Enable notifications", isOn: $notifications)

// Custom value text instead of On/Off; accessibilityValue must match
Toggle(isOn: $displayMode) {
Text("Display Mode")
}
.accessibilityValue(displayMode ? "Dark" : "Light")
}
}
}

Acceptance Checks

The component’s test spec — an optional body of checks for verification.

Traits & semantics

  • The switch is a single accessible element carrying the switch trait, its name, and its on/off value; no separate static-text element duplicates the label.

VoiceOver

  • VoiceOver speaks the setting name, the switch role, and the current state.
  • When custom value wording is used, VoiceOver announces that wording (e.g., "Dark"/"Light"), not generic On/Off.
  • Double-tapping flips the switch and the announced state updates.
  • Repeated switches each speak a distinct name.

Switch Control & Full Keyboard Access

  • The switch is reachable and togglable via Switch Control and a hardware keyboard, with the state change announced.

Dynamic Type

  • The switch's label scales with Dynamic Type and stays fully visible at accessibility text sizes.

Visual

  • The off state is distinguishable from on by more than color, with the off-state fill meeting 3:1 contrast against its background.