Mobile WCAG 2.1 Testing: Automated Tools and Manual Audit Checklist
WCAG 2.1 was the first version of the Web Content Accessibility Guidelines to explicitly address mobile. Applying it to native iOS and Android apps requires mapping each criterion to platform-specific implementation patterns and choosing the right automated tools for coverage. This guide gives you the full picture.
WCAG 2.1 added 17 new success criteria over WCAG 2.0, and 12 of them were specifically designed with mobile and touch interfaces in mind. Despite this, most mobile development teams treat accessibility as a web concern, applying WCAG loosely or not at all to their native apps.
The legal and practical stakes are real. In the United States, Section 508 and the ADA have been applied to mobile apps. In the EU, the European Accessibility Act mandates mobile app compliance from 2025. Beyond compliance, roughly 26% of adults have some form of disability — a significant portion of your user base.
This guide maps WCAG 2.1 success criteria to mobile-specific implementation, covers the best automated tools for each platform, and provides a structured manual audit checklist.
Mapping WCAG 2.1 to Mobile
WCAG criteria use web terminology, but each criterion has a direct mobile equivalent. Here are the most critical ones:
1.1.1 Non-Text Content (Level A)
Every non-decorative image, icon, and graphic must have a text alternative.
iOS implementation:
// Correct — descriptive label
imageView.accessibilityLabel = "Profile photo of Jane Smith"
// Decorative images must be excluded from the accessibility tree
decorativeBackground.isAccessibilityElement = false
// Icon buttons need labels
let shareButton = UIButton()
shareButton.setImage(UIImage(systemName: "square.and.arrow.up"), for: .normal)
shareButton.accessibilityLabel = "Share post"Android implementation:
// Correct
imageView.contentDescription = "Profile photo of Jane Smith"
// Decorative
decorativeView.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
// Icon button
shareButton.contentDescription = "Share post"Automated detection: Google Accessibility Scanner and Axe Mobile both flag missing content descriptions. ATF's SpeakableTextPresentCheck catches these in Espresso tests.
1.4.3 Contrast (Minimum, Level AA)
Text must have a contrast ratio of at least 4.5:1 against its background (3:1 for large text). This is one of the most commonly violated criteria on mobile due to custom themes and dark mode handling.
Test approach: Automated tools (Accessibility Scanner, Axe Mobile) can check contrast for static screens. Dynamic content with computed colors requires manual checking with a contrast analyzer.
Minimum ratios:
- Normal text (< 18pt / 14pt bold): 4.5:1
- Large text (≥ 18pt / 14pt bold): 3:1
- UI components and graphical objects: 3:1 (WCAG 1.4.11)
1.4.4 Resize Text (Level AA)
Text must be resizable up to 200% without loss of content or functionality. On mobile, this maps to Dynamic Type (iOS) and font size accessibility settings (Android).
// iOS — use Dynamic Type styles
label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true
// Don't do this — fixed font size breaks Dynamic Type
label.font = UIFont.systemFont(ofSize: 14) // WRONG for Dynamic Type support// Android — use sp units (not dp) for text
// In XML:
// android:textSize="16sp"
// Test with: adb shell settings put system font_scale 2.02.4.3 Focus Order (Level A)
The navigation sequence must be logical and consistent. On mobile, this means the order in which VoiceOver/TalkBack focuses elements must match reading order.
iOS focus order testing:
// Override accessibilityElements to control focus order
override var accessibilityElements: [Any]? {
get {
return [labelTitle, labelSubtitle, buttonPrimary, buttonSecondary]
}
set { }
}Android traversal order testing:
<!-- Use accessibilityTraversalAfter/Before to set explicit order -->
<Button
android:id="@+id/btn_submit"
android:accessibilityTraversalAfter="@id/field_cvv"
... />2.5.1 Pointer Gestures (Level A)
Functionality using multipoint or path-based gestures must also be achievable with a single pointer. This means any pinch-to-zoom, swipe-to-delete, or custom gesture must have an alternative.
2.5.3 Label in Name (Level A)
For UI elements with visible text labels, the accessible name must contain the visible label text. This is critical for voice control users on iOS (Voice Control) and Android (Voice Access).
// WRONG — accessible name doesn't match visible label
button.setTitle("Buy Now", for: .normal)
button.accessibilityLabel = "Purchase item" // Voice Control users say "tap Buy Now" and nothing happens
// CORRECT — accessible name includes visible text
button.accessibilityLabel = "Buy Now" // or omit and let it inherit from title4.1.2 Name, Role, Value (Level A)
Every UI component must expose its name, role, and state to assistive technologies. This is the catch-all criterion for custom components.
// Custom slider — must expose all three
customSlider.accessibilityLabel = "Volume" // name
customSlider.accessibilityTraits = .adjustable // role
customSlider.accessibilityValue = "75 percent" // value
// Implement increment/decrement for swipe adjustments
override func accessibilityIncrement() {
value = min(100, value + 10)
accessibilityValue = "\(value) percent"
}
override func accessibilityDecrement() {
value = max(0, value - 10)
accessibilityValue = "\(value) percent"
}// Android custom view
override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo) {
super.onInitializeAccessibilityNodeInfo(info)
info.className = SeekBar::class.java.name // role
info.contentDescription = "Volume" // name
info.stateDescription = "$value percent" // value
}Touch Target Size Requirements
WCAG 2.5.5 (Level AAA) recommends 44×44 CSS pixels. WCAG 2.5.8 (Level AA, introduced in WCAG 2.2) requires a minimum of 24×24 CSS pixels.
Platform-specific guidelines are stricter than WCAG minimums:
| Platform | Minimum Target Size | Recommended |
|---|---|---|
| iOS HIG | 44×44 points | 44×44 points |
| Android Material | 48×48 dp | 48×48 dp |
| WCAG 2.5.5 (AAA) | 44×44 CSS px | — |
| WCAG 2.5.8 (AA) | 24×24 CSS px | — |
For icon buttons smaller than the minimum, use padding or TouchDelegate (Android) / accessibilityFrame (iOS) to extend the tap area without changing visual size:
// iOS — extend touch target via accessibilityFrame
override var accessibilityFrame: CGRect {
let frame = super.accessibilityFrame
return frame.insetBy(dx: -10, dy: -10) // extend by 10pt on each side
}// Android — extend touch target with TouchDelegate
val parent = button.parent as View
parent.post {
val touchArea = Rect()
button.getHitRect(touchArea)
touchArea.inset(-20, -20) // extend by 20px
parent.touchDelegate = TouchDelegate(touchArea, button)
}Automated Tools
Google Accessibility Scanner (Android)
The Accessibility Scanner app overlays your running app with issue annotations. Run it against every screen in your app:
- Install from the Play Store
- Enable in Accessibility settings
- Navigate through your app — the scanner captures screenshots with issue overlays
- Export results as a report
Checks: content descriptions, touch targets, contrast, clickable items.
Xcode Accessibility Inspector (iOS)
Built into Xcode. Use it to inspect the accessibility tree and run automated audits:
- Open via Xcode → Open Developer Tool → Accessibility Inspector
- Connect to a simulator or device
- Click the audit button (triangle icon) to run a full scan
Axe Mobile (Deque)
Axe Mobile is the mobile counterpart to axe-core. It provides a runtime SDK that runs accessibility rules against your live app:
# iOS
pod <span class="hljs-string">'AxeMobile'
<span class="hljs-comment"># Android
implementation <span class="hljs-string">'com.deque.android:axe-android:1.+'Axe Mobile integrates with CI via its reporting API and maps violations directly to WCAG criteria.
Deque WorldSpace Comply
An enterprise tool for systematic WCAG auditing across mobile and web. It manages audit checklists, tracks remediation, and generates compliance reports suitable for legal review.
Manual Audit Checklist
Automated tools catch approximately 30-40% of accessibility issues. The rest require manual testing with a real screen reader.
iOS VoiceOver Manual Checklist
- Enable VoiceOver (Settings → Accessibility → VoiceOver)
- Navigate every screen by swiping right — verify logical order
- Double-tap every interactive element — verify activation works
- Verify every image has a meaningful announcement (or is skipped if decorative)
- Verify form fields announce their purpose before and after focus
- Verify error messages are announced when they appear
- Verify modal dialogs trap focus (no elements outside modal are reachable)
- Verify scroll views can be scrolled with three-finger swipe
- Test with Dynamic Type set to Accessibility Extra Extra Extra Large
- Test with Reduce Motion enabled (Settings → Accessibility → Motion)
Android TalkBack Manual Checklist
- Enable TalkBack (Settings → Accessibility → TalkBack)
- Navigate every screen by swiping right — verify logical order
- Double-tap every interactive element — verify activation works
- Verify every image has a meaningful content description
- Verify form field labels are announced before content description
- Verify toast messages and snackbars are announced
- Verify modal dialogs trap focus
- Verify RecyclerView items have unique, descriptive announcements
- Test with font size set to largest (Settings → Display → Font Size)
- Test with high contrast text enabled
Test Matrix Template
Use this matrix to track coverage across WCAG criteria, features, and platforms:
| WCAG Criterion | Feature | iOS Auto | iOS Manual | Android Auto | Android Manual | Status |
|---|---|---|---|---|---|---|
| 1.1.1 Non-text content | Product images | Axe Mobile | VoiceOver | Scanner | TalkBack | Pass |
| 1.4.3 Contrast | Login form | Axe Mobile | Inspector | Scanner | — | Fail |
| 2.4.3 Focus order | Checkout flow | — | VoiceOver | — | TalkBack | In progress |
| 4.1.2 Name/role/value | Custom slider | XCTest | VoiceOver | Espresso | TalkBack | Pass |
Maintain this matrix in your project wiki and update it after each sprint. For continuous monitoring, tools like HelpMeTest can run accessibility checks against your app on a schedule and flag new violations as they appear, keeping your matrix current without manual effort.
WCAG 2.1 mobile compliance is achievable with a structured approach. Automate what you can, maintain a disciplined manual audit process for the rest, and treat accessibility as a first-class quality metric tracked alongside crash rates and test coverage.