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
Sliderso VoiceOver exposes the adjustable behavior automatically (swipe up or down to change the value) and Switch Control can adjust it. SwiftUI has no.adjustabletrait to add; the native control provides adjustability, and a custom-drawn slider gets it fromaccessibilityAdjustableAction(perglobal.custom-control-representation). - The slider has a specific accessible name. Supply it with the
Sliderlabel closure (Slider(value:in:) { Text("Brightness") }), whose text becomes the accessible name, or pair a visibleTextlabel with.accessibilityLabel. A bareSliderhas no inherent label. - Set
.accessibilityValueto 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
StepperandTextFieldfor fine and direct control.- Icon-only increment and decrement buttons each need an
.accessibilityLabel(e.g., "Decrease brightness", "Increase brightness").
- Icon-only increment and decrement buttons each need an
- 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
.adjustabletrait; 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
.accessibilityValueat 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, aTextFieldfor direct numeric entry, or a combination, as long as at least one single-tap path adjusts the value. - The slider may show
minimumValueLabelandmaximumValueLabelfor 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.
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
.adjustabletrait is present (SwiftUI has none). A custom slider exposes adjustability throughaccessibilityAdjustableAction.
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.