Accessibility12 min read

ADA/Accessibility Compliance Checklist for Mobile Apps

A comprehensive guide to making mobile applications accessible to all users — from screen reader support to motor accessibility.

Why Accessibility Matters

Accessibility isn't just about compliance — it's about ensuring everyone can use your app. Approximately 15% of the world's population lives with some form of disability. That's over a billion people.

Beyond the moral imperative:

  • Legal requirements — ADA, Section 508, and international regulations
  • Market opportunity — Accessible apps reach more users
  • Better UX for everyone — Accessibility improvements often benefit all users
  • App store visibility — Both Apple and Google promote accessible apps

This guide provides a practical checklist for mobile accessibility, organized by disability category and implementation priority.

Visual Accessibility

Screen Reader Support

Screen readers (VoiceOver on iOS, TalkBack on Android) are essential for blind and low-vision users.

Labels and Hints

// iOS
button.accessibilityLabel = "Submit order"
button.accessibilityHint = "Double tap to submit your order for processing"

// Avoid redundant type information
// Bad: "Submit button"
// Good: "Submit order"
// Android
button.contentDescription = "Submit order"
button.accessibilityDelegate = object : View.AccessibilityDelegate() {
    override fun onInitializeAccessibilityNodeInfo(
        host: View,
        info: AccessibilityNodeInfo
    ) {
        super.onInitializeAccessibilityNodeInfo(host, info)
        info.hintText = "Double tap to submit your order for processing"
    }
}

Element Ordering

// iOS: Control focus order
view.accessibilityElements = [headerLabel, contentView, actionButton]

// Group related elements
containerView.isAccessibilityElement = false
containerView.accessibilityElements = [childElements]
<!-- Android: Traversal order -->
<Button
    android:id="@+id/submitButton"
    android:accessibilityTraversalAfter="@id/formFields"
    android:accessibilityTraversalBefore="@id/cancelButton" />

Dynamic Content Announcements

// iOS: Announce changes
UIAccessibility.post(
    notification: .announcement,
    argument: "Order submitted successfully"
)

// Screen layout changed
UIAccessibility.post(notification: .layoutChanged, argument: newFocusElement)
// Android
view.announceForAccessibility("Order submitted successfully")

Color and Contrast

Minimum Contrast Ratios

Text SizeMinimum Ratio (AA)Enhanced (AAA)
Normal text4.5:17:1
Large text (18pt+)3:14.5:1
UI components3:13:1

Testing Contrast

// Calculate contrast ratio
func contrastRatio(foreground: UIColor, background: UIColor) -> CGFloat {
    let fgLuminance = relativeLuminance(foreground)
    let bgLuminance = relativeLuminance(background)

    let lighter = max(fgLuminance, bgLuminance)
    let darker = min(fgLuminance, bgLuminance)

    return (lighter + 0.05) / (darker + 0.05)
}

Color Independence

Never use color as the only indicator:

// Bad: Only color indicates error
textField.layer.borderColor = UIColor.red.cgColor

// Good: Color + icon + text
textField.layer.borderColor = UIColor.red.cgColor
errorIcon.isHidden = false
errorLabel.text = "Please enter a valid email"

Text Scaling

Support dynamic type for users who need larger text:

// iOS: Dynamic Type
label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true

// SwiftUI
Text("Hello")
    .font(.body)
    .dynamicTypeSize(.large ... .accessibility5)
<!-- Android: Scalable text -->
<TextView
    android:textSize="16sp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Motor Accessibility

Touch Target Size

Minimum touch target: 44x44 points (iOS) / 48x48dp (Android)

// iOS: Expand hit area
class LargeTouchButton: UIButton {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let expandedBounds = bounds.insetBy(dx: -10, dy: -10)
        return expandedBounds.contains(point)
    }
}

Gesture Alternatives

Provide alternatives to complex gestures:

// If swipe-to-delete is primary, also provide:
// 1. Edit mode with delete buttons
// 2. Long-press context menu
// 3. Accessibility custom actions

cell.accessibilityCustomActions = [
    UIAccessibilityCustomAction(
        name: "Delete",
        target: self,
        selector: #selector(deleteItem)
    )
]

Switch Control Support

Ensure all functionality is reachable via switch control:

// Make custom controls focusable
customControl.isAccessibilityElement = true
customControl.accessibilityTraits = .button

// Avoid time-dependent interactions
// Bad: Auto-dismissing toast after 2 seconds
// Good: Dismissable notification with button

Hearing Accessibility

Captions and Transcripts

// AVFoundation captions
let asset = AVAsset(url: videoURL)
let group = asset.mediaSelectionGroup(forMediaCharacteristic: .legible)
let options = group?.options.filter {
    $0.mediaType == .closedCaption
}

Visual Indicators for Audio

Replace audio-only feedback with visual alternatives:

// Bad: Only sound on error
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)

// Good: Sound + haptic + visual
if UIAccessibility.isVoiceOverRunning || !userPrefersSounds {
    showVisualFeedback()
}
playSound()
provideHapticFeedback()

Cognitive Accessibility

Clear Language

  • Use simple, direct language
  • Avoid jargon and abbreviations
  • Provide definitions for technical terms

Consistent Navigation

  • Maintain consistent navigation patterns
  • Use familiar icons with labels
  • Provide clear back/cancel options

Error Prevention and Recovery

// Confirm destructive actions
let alert = UIAlertController(
    title: "Delete Account?",
    message: "This action cannot be undone. All your data will be permanently deleted.",
    preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
alert.addAction(UIAlertAction(title: "Delete", style: .destructive) { _ in
    self.deleteAccount()
})

Reduce Motion

Respect user preferences for reduced motion:

// iOS
if UIAccessibility.isReduceMotionEnabled {
    // Use fade instead of slide animations
    transition = .crossDissolve
} else {
    transition = .slide
}

// SwiftUI
withAnimation(reduceMotion ? nil : .default) {
    // Animation
}

Testing Accessibility

Automated Testing

// XCTest accessibility audit
func testAccessibility() throws {
    let app = XCUIApplication()
    app.launch()

    try app.performAccessibilityAudit()
}

Manual Testing Checklist

Screen Reader Testing

  • Navigate entire app with VoiceOver/TalkBack
  • Verify all elements have meaningful labels
  • Check reading order is logical
  • Confirm all actions are accessible
  • Test with screen reader at different speeds

Visual Testing

  • Test with largest text size
  • Verify contrast in light and dark modes
  • Check color independence
  • Test with color blindness simulators
  • Verify focus indicators are visible

Motor Testing

  • Test with Switch Control / Switch Access
  • Verify all touch targets meet minimum size
  • Check for gesture alternatives
  • Test with one hand
  • Verify no time-dependent interactions

Cognitive Testing

  • Review all text for clarity
  • Check error messages are helpful
  • Verify confirmation for destructive actions
  • Test with reduced motion enabled
  • Check navigation consistency

Implementation Checklist

Critical (P0)

  • All images have alt text / contentDescription
  • All form fields have labels
  • Color is not the only indicator
  • Touch targets are 44x44 / 48x48 minimum
  • App works with screen reader

High Priority (P1)

  • Supports dynamic text sizing
  • Meets WCAG AA contrast requirements
  • Logical focus order
  • Error messages are descriptive
  • No time-dependent interactions

Medium Priority (P2)

  • Supports reduced motion
  • Gesture alternatives available
  • Captions for video content
  • Custom actions for complex interactions
  • Semantic headings structure

Continuous

  • Accessibility audit in CI pipeline
  • User testing with people with disabilities
  • Accessibility training for team
  • Documentation of accessibility features

Resources

Guidelines

Testing Tools

  • Accessibility Inspector (Xcode)
  • Accessibility Scanner (Android)
  • Colour Contrast Analyser
  • axe DevTools

Conclusion

Accessibility is not a feature — it's a quality attribute that should be present from the start. Building accessibly:

  1. Start early — Retrofitting is harder than building right
  2. Test continuously — Include in your CI pipeline
  3. Listen to users — Real feedback from users with disabilities is invaluable
  4. Train your team — Everyone should understand accessibility basics

An accessible app is a better app for everyone.


Accessibility guidelines refined through enterprise mobile development with strict compliance requirements.

Abraham Jeyaraj

Written by Abraham Jeyaraj

AI-Powered Solutions Architect with 20+ years of experience in enterprise software development.