Mobile App Accessibility: VoiceOver, TalkBack and WCAG in Practice
The app was rejected from the App Store under guideline 1.1, or a request came from a corporate client requiring WCAG 2.1 AA—both situations mean one thing: accessibility was not built into the architecture from the start, and now it needs to be retrofitted into a finished product. It hurts.
Why "Add Accessibility Later" Doesn't Work
The most common problem—developers perceive VoiceOver and TalkBack as cosmetics. Add accessibilityLabel, launch Screen Reader and wonder why focus jumps from the "Buy" button to a decorative icon in the corner.
On iOS, the error lives in incorrect element grouping. If UIStackView contains an icon + text + price, VoiceOver will read them as three separate elements instead of one. Solution—isAccessibilityElement = false on the container + accessibilityElements with the right order, or shouldGroupAccessibilityChildren = true. Seems minor, but this is exactly what makes the difference between "formally works" and "a blind user can buy a product in 30 seconds."
On Android, the situation is mirrored: contentDescription is set everywhere, including ImageViews that are purely decorative. TalkBack starts reading "arrow icon" between every meaningful element. Correct—android:importantForAccessibility="no" for decoration and explicit contentDescription only where it makes sense.
Dynamic Type and Font Scaling
iOS Dynamic Type breaks layout predictably: fixed line heights in UILabel, hardcoded frame in Auto Layout, numberOfLines = 1 without adjustsFontSizeToFitWidth. When a user sets font size to XXL in settings, text gets cut off or overlaps neighboring elements.
Proper implementation uses .font = UIFont.preferredFont(forTextStyle: .body) with adjustsFontForContentSizeCategory = true and numberOfLines = 0 everywhere dynamic content appears. In SwiftUI, this works out of the box via .dynamicTypeSize() modifier.
On the Flutter side, the equivalent—textScaleFactor via MediaQuery. Material 3 components support scaling natively, but custom widgets require explicit consideration.
WCAG 2.1 in Mobile Context
Mobile apps are formally not required to follow WCAG (it was written for the web), but WCAG 2.1 + mobile supplements became de facto standard for corporate tenders and government procurement.
Critical criteria as applied to mobile:
- 1.4.3 Contrast Minimum—text to background contrast ratio minimum 4.5:1. Check via Xcode Accessibility Inspector or Android Studio Layout Inspector
- 2.4.7 Focus Visible—when working with an external keyboard on iPad/Android tablet, focus must be visible. Often forgotten scenario
- 2.5.8 Target Size (AA)—minimum 24x24dp for interactive elements, recommended 44pt/48dp
-
4.1.3 Status Messages—form error notifications must be voiced via
UIAccessibility.post(notification: .announcement)orAccessibilityNodeInfo.RoleDescriptionon Android
How We Build the Process
Audit starts with Accessibility Inspector in Xcode and TalkBack developer settings on Android—go through all screens with Screen Reader enabled and note every case requiring more than 3 actions to complete the target operation.
Next—automated checks. XCUITest supports accessibility assertions; for Android, use Accessibility Test Framework (ATF), which is built into Espresso. This catches regressions on CI.
Final stage—testing with real users using assistive technology. No automation replaces this.
| Tool | Platform | What It Checks |
|---|---|---|
| Xcode Accessibility Inspector | iOS/macOS | Labels, contrast, focus order |
| Android Accessibility Scanner | Android | Contrast, touch target sizes |
| Deque axe DevTools | Cross-platform | WCAG compliance |
| VoiceOver (iOS) | iOS | Screen Reader navigation |
| TalkBack (Android) | Android | Screen Reader navigation |
Timeframe
Audit and basic fixes to an existing app—2 to 5 weeks depending on number of screens and depth of issues. Implementing accessibility from scratch in a new project practically doesn't affect timeframes with proper component system design—budget 10-15% overhead on UI layer development.







