Skip to content
All essays
iOSMarch 27, 202512 min

Swift Accessibility Guide: Inclusive iOS Development

Make your iOS apps accessible to everyone. VoiceOver, Dynamic Type, and assistive technologies.

Ü
Ümit Uz
Mobile & Full Stack Developer

Accessibility ensures your app is usable by everyone. Learn to implement accessibility features in iOS apps.

Accessibility Labels

Basic Labels

swift
import SwiftUI

struct AccessibilityView: View {
    var body: some View {
        VStack {
            // Good accessibility
            Image(systemName: "star.fill")
                .accessibilityLabel("Favorite")
                .accessibilityHint("Mark as favorite")

            // Bad accessibility
            Image(systemName: "star.fill")
        }
    }
}

Custom Accessibility Labels

swift
struct CustomAccessibilityView: View {
    @State private var isOn = false

    var body: some View {
        Toggle("Dark Mode", isOn: $isOn)
            .accessibilityLabel("Enable dark mode")
            .accessibilityHint("Changes app appearance to dark theme")
    }
}

VoiceOver Support

Screen Reader Support

swift
struct VoiceOverView: View {
    @State private var selectedRating = 3

    var body: some View {
        VStack {
            // Custom accessibility for rating
            HStack {
                ForEach(1...5, id: \.self) { rating in
                    Image(systemName: rating <= selectedRating ? "star.fill" : "star")
                        .accessibilityLabel(rating <= selectedRating ? "Selected" : "Unselected")
                        .accessibilityAddTraits(rating <= selectedRating ? [.isSelected] : [])
                        .onTapGesture {
                            selectedRating = rating
                        }
                }
            }
            .accessibilityLabel("Rating")
            .accessibilityValue("\(selectedRating) out of 5")
        }
    }
}

Accessibility Actions

swift
struct AccessibilityActionsView: View {
    @State private var isFavorite = false

    var body: some View {
        Image(systemName: "heart")
            .foregroundColor(isFavorite ? .red : .gray)
            .accessibilityLabel(isFavorite ? "Remove from favorites" : "Add to favorites")
            .accessibilityAction(.default) {
                isFavorite.toggle()
            }
            .accessibilityAction(.magicTap) {
                // Double-tap with two fingers
                isFavorite.toggle()
            }
    }
}

Dynamic Type

Support Text Scaling

swift
struct DynamicTypeView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Headline")
                .font(.headline)
                .dynamicTypeSize(...DynamicTypeSize.accessibility3)

            Text("Body")
                .font(.body)
                .dynamicTypeSize(...DynamicTypeSize.accessibility3)

            Text("Caption")
                .font(.caption)
                .dynamicTypeSize(...DynamicTypeSize.accessibility3)
        }
        .padding()
    }
}

Scalable Layouts

swift
struct ScalableView: View {
    @Environment(\.dynamicTypeSize) var dynamicTypeSize

    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: dynamicTypeSize == .accessibility1 ? 24 : 16) {
                Text("Dynamic Type Support")
                    .font(.title)
                    .fontWeight(.bold)

                Text("This text scales with your device settings")
                    .font(.body)
            }
            .padding()
        }
    }
}

Accessibility Elements

Accessible Images

swift
struct AccessibleImageView: View {
    var body: some View {
        // Decorative image
        Image(systemName: "star.fill")
            .accessibilityHidden(true)

        // Meaningful image
        Image(systemName: "person.crop.circle.fill")
            .accessibilityLabel("Profile picture")

        // Image with description
        Image(systemName: "photo")
            .accessibilityLabel("Photo of a sunset")
            .accessibilityHint("Tap to view full size")
    }
}

Accessible Groups

swift
struct AccessibilityGroupsView: View {
    let user = User(name: "John Doe", email: "john@example.com")

    var body: some View {
        HStack {
            Circle()
                .fill(Color.blue)
                .frame(width: 50, height: 50)

            VStack(alignment: .leading) {
                Text(user.name)
                    .font(.headline)
                Text(user.email)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
        .accessibilityElement(children: .combine)
        .accessibilityLabel("User: \(user.name), \(user.email)")
    }
}

struct User {
    let name: String
    let email: String
}

Semantic UI

Semantic Views

swift
struct SemanticView: View {
    var body: some View {
        VStack {
            // Header
            Text("Welcome")
                .font(.title)
                .accessibilityAddTraits(.isHeader)

            // Button
            Button("Get Started") {
                // Action
            }
            .accessibilityHint("Starts the onboarding process")

            // Link
            Text("Learn more")
                .accessibilityAddTraits(.isLink)
                .onTapGesture {
                    // Navigation
                }
        }
    }
}

Accessibility Traits

Common Traits

swift
struct AccessibilityTraitsView: View {
    @State private var isSelected = false

    var body: some View {
        VStack {
            // Button trait
            Button("Tap me") {}
                .accessibilityAddTraits(.isButton)

            // Selected state
            Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
                .accessibilityAddTraits(isSelected ? [.isSelected] : [])

            // Static text
            Text("Information")
                .accessibilityAddTraits(.isStaticText)

            // Header
            Text("Section Title")
                .accessibilityAddTraits(.isHeader)
        }
    }
}

Accessibility Identifier

UI Testing Support

swift
struct TestableView: View {
    var body: some View {
        VStack {
            TextField("Username", text: $username)
                .accessibilityIdentifier("usernameField")

            SecureField("Password", text: $password)
                .accessibilityIdentifier("passwordField")

            Button("Login") {
                // Login action
            }
            .accessibilityIdentifier("loginButton")
        }
    }
}

Reduced Motion

Support Motion Preferences

swift
struct ReducedMotionView: View {
    @Environment(\.accessibilityReduceMotion) var reduceMotion

    @State private var isAnimating = false

    var body: some View {
        Circle()
            .fill(Color.blue)
            .frame(width: 100, height: 100)
            .scaleEffect(isAnimating ? 1.5 : 1.0)
            .animation(reduceMotion ? nil : .spring(), value: isAnimating)
            .onTapGesture {
                isAnimating.toggle()
            }
    }
}

High Contrast

Support Dark Mode

swift
struct HighContrastView: View {
    @Environment(\.accessibilityReduceTransparency) var reduceTransparency
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        ZStack {
            if reduceTransparency {
                Color.black
            } else {
                Color.black.opacity(0.8)
            }

            Text("High Contrast Content")
                .foregroundColor(.white)
                .padding()
        }
        .cornerRadius(reduceTransparency ? 0 : 20)
    }
}

Best Practices

  1. 1Labels: Provide clear, descriptive labels
  2. 2Traits: Use appropriate accessibility traits
  3. 3Focus: Manage accessibility focus
  4. 4Testing: Test with VoiceOver
  5. 5Feedback: Provide meaningful feedback
  6. 6Language: Support right-to-left languages
  7. 7Testing: Use Accessibility Inspector
  8. 8Users: Test with real accessibility users

Accessibility makes your app usable by everyone!

Related essays

Next essay
Advanced Swift Machine Learning: Custom Models