Skip to main content
iOS / SwiftUI · WCAG 2.2 AA

Slider

A native SwiftUI Slider that VoiceOver adjusts by swiping up or down, paired with single-tap controls so the value is adjustable without a drag gesture.

Selection

The criteria an agent checks before retrieving this component.

Use when

  • Use when the user adjusts a value across a continuous or stepped numeric range by moving a thumb between a minimum and maximum (e.g., "Brightness", "Volume", "Speed"). Uses a native SwiftUI Slider, which VoiceOver adjusts by swiping up or down.

Try a different component when

  • Do not use when the value changes in discrete single increments and a compact plus/minus control fits better (use stepper.basic).
  • Do not use when the choice is among a small fixed set of labeled options rather than a numeric range (use select.segmented).
  • Do not use when the control is a simple on/off setting (use switch.basic).

Must Haves

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

  • Use a native Slider so VoiceOver exposes the adjustable behavior automatically (swipe up or down to change the value) and Switch Control can adjust it. SwiftUI has no .adjustable trait to add; the native control provides adjustability, and a custom-drawn slider gets it from accessibilityAdjustableAction (per global.custom-control-representation).
  • The slider has a specific accessible name. Supply it with the Slider label closure (Slider(value:in:) { Text("Brightness") }), whose text becomes the accessible name, or pair a visible Text label with .accessibilityLabel. A bare Slider has no inherent label.
  • Set .accessibilityValue to a meaningful value with units when the default percentage is not self-explanatory (e.g., "$50", "Medium", "72 degrees").
  • Provide a single-tap alternative to the drag gesture so the value can be changed without a path-based gesture (WCAG 2.5.1): decrement and increment buttons, or a paired Stepper and TextField for fine and direct control.
    • Icon-only increment and decrement buttons each need an .accessibilityLabel (e.g., "Decrease brightness", "Increase brightness").
  • Give repeated sliders on one screen unique accessible names.
  • 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 add a .adjustable trait; SwiftUI has no such trait (it exists only in UIKit). For a custom slider, confer adjustability with .accessibilityAdjustableAction, not a trait.
  • Do not ship a slider adjustable only by dragging; provide a single-tap alternative (WCAG 2.5.1).
  • Do not leave the slider without a visible label and an accessible name.
  • Do not leave .accessibilityValue at the default percentage when the value carries meaningful units the user needs (e.g., currency, temperature).
  • Do not create icon-only increment or decrement buttons without accessible names.

Customizable

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

  • The single-tap alternative is the engineer's choice: increment and decrement buttons, a paired Stepper, a TextField for direct numeric entry, or a combination, as long as at least one single-tap path adjusts the value.
  • The slider may show minimumValueLabel and maximumValueLabel for visible bounds; these are supplementary and do not replace the accessible name or value.
  • step: may be set for discrete stops or omitted for continuous adjustment; both remain adjustable to VoiceOver.

Golden Pattern

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

SWIFT
import SwiftUI

struct SliderBasicDemo: View {
@State private var brightness = 50.0

var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text("Brightness")

HStack {
// Single-tap alternative to dragging; icon-only buttons need names.
Button {
brightness = max(0, brightness - 10)
} label: {
Image(systemName: "sun.min")
}
.accessibilityLabel("Decrease brightness")

Slider(value: $brightness, in: 0...100, step: 10) {
Text("Brightness") // becomes the accessible name
} minimumValueLabel: {
Text("0")
} maximumValueLabel: {
Text("100")
}

Button {
brightness = min(100, brightness + 10)
} label: {
Image(systemName: "sun.max.fill")
}
.accessibilityLabel("Increase brightness")
}
}
}
}

Acceptance Checks

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

Traits & semantics

  • The slider is announced as adjustable, and no manual .adjustable trait is present (SwiftUI has none). A custom slider exposes adjustability through accessibilityAdjustableAction.

VoiceOver

  • The slider speaks its specific name (e.g., "Brightness") and its current value; swiping up or down changes the value and the new value is announced.
  • Where the value carries units, VoiceOver speaks them (e.g., "50 percent", "$50"), not a bare number that would be ambiguous.
  • The increment and decrement buttons each speak a distinct name.

Switch Control & Full Keyboard Access

  • The slider is adjustable via Switch Control and a hardware keyboard, and the single-tap increment and decrement controls are reachable and activatable by both.

Dynamic Type

  • The slider's label and value text scale with Dynamic Type and stay fully visible at accessibility text sizes.