Skip to content
intermediate Phase 14 · Advanced iOS

Accessibility & VoiceOver

Make iOS apps accessible: VoiceOver, Dynamic Type, contrast, and accessibility audit.

45m
2 problems
Topic Progress 0%

VoiceOver Support

What is VoiceOver?

VoiceOver is Apple screen reader for blind and low-vision users. It reads aloud the content on screen and provides gesture-based navigation.

Accessibility Labels

Every interactive element needs an accessibility label:

// SwiftUI
Image(systemName: "heart.fill")
    .accessibilityLabel("Favorite")

Button(action: addToCart) {
    Image(systemName: "cart")
}
.accessibilityLabel("Add to cart")

// UIKit
addToCartButton.accessibilityLabel = "Add to cart"

Accessibility Hints

Provide context about what an action does:

Button(action: toggleFavorite) {
    Image(systemName: isFavorite ? "heart.fill" : "heart")
}
.accessibilityLabel(isFavorite ? "Remove from favorites" : "Add to favorites")
.accessibilityHint("Double tap to toggle favorite status")

Accessibility Traits

Identify the role of UI elements:

// SwiftUI
Text("Breaking News")
    .accessibilityAddTraits(.isHeader)

TextField("Email", text: $email)
    .accessibilityAddTraits(.isSearchField)

// UIKit
headlineLabel.accessibilityTraits = .header
searchField.accessibilityTraits = .searchField

VoiceOver Navigation

Test navigation flow:

  1. Enable VoiceOver in Settings > Accessibility > VoiceOver
  2. Swipe right to move to next element
  3. Swipe left to move to previous element
  4. Double-tap to activate
  5. Use rotor (two-finger twist) to navigate by heading, link, etc.

Dynamic Type

What is Dynamic Type?

Dynamic Type lets users adjust text size across all apps. Your app should respect their preferred text size.

Supporting Dynamic Type in SwiftUI

// SwiftUI automatically supports Dynamic Type with system fonts
Text("Hello World")
    .font(.body)

// Custom fonts should use scaled metrics
Text("Title")
    .font(.custom("MyFont", size: 17).scaledMetric(relativeTo: .body))

Supporting Dynamic Type in UIKit

// Use preferred font
headlineLabel.font = UIFont.preferredFont(forTextStyle: .headline)
headlineLabel.adjustsFontForContentSizeCategory = true

// Custom fonts with scaling
let customFont = UIFont(name: "MyFont", size: 17)!
headlineLabel.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: customFont)

Layout Adaptation

Adjust layouts for larger text sizes:

struct AdaptiveLayout: View {
    @Environment(\.dynamicTypeSize) var typeSize
    
    var body: some View {
        if typeSize >= .accessibility2 {
            // Stack vertically for large text
            VStack {
                imageView
                textContent
            }
        } else {
            // Side by side for normal text
            HStack {
                imageView
                textContent
            }
        }
    }
}

Testing Dynamic Type

  1. Enable in Settings > Accessibility > Display and Text Size > Larger Text
  2. Use the Xcode Environment preview to test different sizes
  3. Test with Accessibility sizes enabled
  4. Ensure no text is clipped or overlapping

Accessibility Audit

Xcode Accessibility Inspector

Use the Accessibility Inspector (Xcode > Open Developer Tool) to:

  • View the accessibility hierarchy
  • Check labels, hints, and traits
  • Identify missing accessibility information
  • Test VoiceOver focus order

Automated Audit

Run an accessibility audit from Xcode:

  1. Select Product > Perform Action > Accessibility Audit
  2. Choose All Issues or specific categories
  3. Review warnings and errors
  4. Fix missing labels, insufficient contrast, etc.

Common Accessibility Issues

  • Missing accessibility labels on images and buttons
  • Empty accessibility groups
  • Insufficient color contrast
  • Text that cannot scale with Dynamic Type
  • Interactive elements that are too small (minimum 44x44 points)
  • Custom controls without accessibility support

Color and Contrast

// Ensure sufficient contrast
Text("Important")
    .foregroundStyle(Color(.label)) // Adapts to light/dark mode

// Avoid using color alone to convey information
HStack {
    Circle().fill(isOnline ? Color.green : Color.red)
    Text(isOnline ? "Online" : "Offline")
}
.accessibilityElement(children: .combine)

Accessibility Testing Checklist

  • All images have accessibility labels
  • All buttons have descriptive labels
  • Dynamic Type is supported
  • Color contrast meets WCAG 2.1 AA standards
  • No information is conveyed by color alone
  • Focus order is logical
  • Custom controls expose correct traits
  • Tested with VoiceOver enabled
  • Tested with large text sizes
  • Tested with reduced motion enabled

Quiz

1. What does .accessibilityLabel do in SwiftUI?

Question 1 options

2. What is the minimum touch target size recommended by Apple?

Question 2 options

3. How do you support Dynamic Type in SwiftUI?

Question 3 options

4. What is the purpose of accessibilityHint?

Question 4 options

Flashcards

Question

What is VoiceOver?

Answer

Apple built-in screen reader that reads aloud screen content and provides gesture-based navigation for blind and low-vision users.

Question

What is Dynamic Type?

Answer

A system setting that lets users choose their preferred text size. Apps should respect this setting and scale text accordingly.

Question

What is the minimum recommended touch target size?

Answer

44x44 points. This ensures interactive elements are large enough for users with motor impairments to tap accurately.

Revision Notes

Key Takeaways

  • 1. Every interactive element needs an accessibility label
  • 2. Support Dynamic Type with system fonts or scaledMetric
  • 3. Minimum touch target size is 44x44 points
  • 4. Use Accessibility Inspector to audit your app
  • 5. Test with VoiceOver and large text sizes regularly

Interview Tips

  • Explain how to implement VoiceOver support in SwiftUI
  • Describe how to support Dynamic Type
  • Discuss common accessibility issues and how to fix them
  • Walk through using the Accessibility Inspector

Cheat Sheet

Accessibility Quick Reference

  • .accessibilityLabel: VoiceOver description
  • .accessibilityHint: Action result description
  • .accessibilityAddTraits: element role
  • Dynamic Type: use system fonts or scaledMetric
  • Minimum touch target: 44x44 points
  • Use Accessibility Inspector for auditing
  • Never use color alone to convey information