Accessibility
Accessibility
Label controls, support Dynamic Type and contrast, and test with VoiceOver to ensure inclusive experiences.
VoiceOver and Labels
All interactive elements must be perceivable to assistive technologies.
Provide meaningful labels and hints.
Example
import SwiftUI
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 12) {
Text("Count: \(count)")
.accessibilityLabel("Current count")
.accessibilityValue("\(count)")
Button("Increment") { count += 1 }
.accessibilityHint("Increases the count by one")
}
.padding()
}
}
In this example, the count is perceivable through both label and value.
Dynamic Type and Contrast
Use system text styles (e.g., .font(.body)) and check color contrast.
Respect reduced motion and increased contrast settings.
Tip: Test with VoiceOver, Larger Text, Bold Text, and different Appearance (Light/Dark).
Use the Accessibility Inspector in Xcode.
Semantics & Traits
Expose clear semantics and traits so assistive tech understands your UI.
Example
import SwiftUI
struct PlanBadge: View {
var body: some View {
VStack {
Image(systemName: "star.fill")
.foregroundStyle(.yellow)
.accessibilityLabel("Favorite")
.accessibilityAddTraits(.isImage)
Text("Premium plan")
}
// Read as one element: "Favorite, Premium plan"
.accessibilityElement(children: .combine)
}
}
In the example above, the image is exposed as an image and the text as a label.
Focus, Order & Grouping
Control reading order and group related elements.
Example
import SwiftUI
struct TotalRow: View {
var total: Double
var body: some View {
HStack {
Text("Total")
.accessibilitySortPriority(2)
Text(total, format: .currency(code: Locale.current.currency?.identifier ?? "USD"))
.accessibilitySortPriority(1)
}
// Alternatively, combine for a single announcement
// .accessibilityElement(children: .combine)
}
}
In the example above, the total is read as one element.
Custom Actions
Expose adjustable and named actions to VoiceOver users.
Example
import SwiftUI
struct QuantityStepper: View {
@State private var qty = 1
var body: some View {
Stepper("Quantity: \(qty)", value: $qty)
.accessibilityValue("\(qty)")
.accessibilityAdjustableAction { direction in
switch direction {
case .increment: qty += 1
case .decrement: qty = max(0, qty - 1)
default: break
}
}
.accessibilityAction(named: Text("Reset")) { qty = 1 }
}
}
In the example above, the stepper has adjustable actions and a named action.
Testing checklist: Verify label, value, hint, traits; reading order; adjustable actions; Dynamic Type; dark/light contrast; and Reduced Motion.