iOS Guide

iOS accessibility cheatsheet

A practical reference for making iPhone and iPad apps usable with VoiceOver, larger text, Switch Control, and system accessibility settings.

All materials

1. Why it matters

  • Better UX for everyone: larger text, clearer focus, less motion sickness.
  • App Store and Apple HIG expect solid accessibility basics.
  • Many fixes are small API choices: labels, traits, and Dynamic Type.

2. Core APIs (UIKit + SwiftUI)

NeedUIKitSwiftUI
Accessible nameaccessibilityLabel.accessibilityLabel()
Hint / how to useaccessibilityHint.accessibilityHint()
Value (slider, switch)accessibilityValue.accessibilityValue()
Role / behavioraccessibilityTraits.accessibilityAddTraits()
Hide decorationisAccessibilityElement = false.accessibilityHidden(true)
Group childrencontainer + combined elements.accessibilityElement(children: .combine)
Custom actionsUIAccessibilityCustomAction.accessibilityAction()

3. VoiceOver labels that work

  • Describe the control, not the visual style: "Delete message", not "Red trash icon".
  • Keep labels short; put extra guidance in the hint.
  • Do not hardcode visible text into the label if the UI label already speaks it - avoid double reading.
  • For icons-only buttons, a label is mandatory.
  • Update labels when state changes (Playing / Paused, Selected / Not selected).
// SwiftUI
Button(action: delete) {
  Image(systemName: "trash")
}
.accessibilityLabel("Delete message")
.accessibilityHint("Removes this message from the chat")

// UIKit
button.accessibilityLabel = "Delete message"
button.accessibilityHint = "Removes this message from the chat"
button.accessibilityTraits = .button

4. Traits and roles

TraitUse when
.buttonTappable action control
.linkOpens another screen / URL
.headerSection title for rotor navigation
.selectedCurrent tab, chip, or selected cell
.adjustableSlider / stepper with swipe up-down
.imageMeaningful image (not decorative)
.updatesFrequentlyLive values (timer, download %)

Pick one clear role. Conflicting traits confuse VoiceOver.

5. Dynamic Type

  • Use text styles (body, headline, footnote), not fixed point sizes only.
  • In UIKit: label.adjustsFontForContentSizeCategory = true with a text style font.
  • In SwiftUI: prefer .font(.body) / semantic styles; test largest Accessibility sizes.
  • Layouts must not clip or overlap at XXXL.
  • Prefer wrapping over truncating critical text.
// UIKit
label.font = .preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true
label.numberOfLines = 0

// SwiftUI
Text("Account settings")
  .font(.title2)
  .fixedSize(horizontal: false, vertical: true)

6. Motion, contrast, and system settings

SettingWhat to do
Reduce MotionReplace large parallax/zooms with fades or no animation
Increase ContrastStrengthen borders and text/background contrast
Bold TextDo not rely on hairline fonts only
Differentiate Without ColorDo not use color alone for errors/states
Button ShapesEnsure tappable text still looks actionable
// SwiftUI Reduce Motion example
@Environment(\.accessibilityReduceMotion) var reduceMotion

withAnimation(reduceMotion ? nil : .easeInOut) {
  isExpanded.toggle()
}

7. Focus order and grouping

  • Reading order should match visual order (top-left to bottom-right in LTR).
  • Group title + subtitle + meta into one element when they form one card.
  • Hide decorative images and separators from VoiceOver.
  • After modal dismiss / navigation, move focus to a sensible element.
  • Custom components need a clear accessibility frame (hit target roughly 44x44 pt).

8. Quick checklist before release

#Check
1Every icon button has a label
2Forms announce errors, not only red color
3Dynamic Type at largest sizes does not break UI
4VoiceOver can complete main user flows
5Reduce Motion has a calm alternative
6Images that matter have descriptions; decorative ones are hidden
7Selected states are exposed with traits/values
8Sheet/dialog titles are announced as headers

9. How to test on device

  1. Settings - Accessibility - VoiceOver - turn on (or use Accessibility Inspector on Mac).
  2. Practice gestures: swipe to move, double-tap to activate, two-finger scrub to go back.
  3. Settings - Display and Text Size - Larger Text - test max sizes.
  4. Enable Reduce Motion and Increase Contrast, then re-check key screens.
  5. For automation: XCTest accessibility audits / Accessibility Inspector warnings.