iOS Accessibility Checklist for the EAA

The European Accessibility Act (EAA) has been mandatory since 28 June 2025 for banking, e-commerce, transport, media and other consumer-facing digital services. National transpositions carry serious penalties — in Spain, the sanctions regime under Ley 11/2023, by reference to Real Decreto Legislativo 1/2013, allows fines of up to one million euros. And no, the famous "grace period until 2030" does not exist for your app: that transitional provision only covers products already in legal use before the deadline.

The technical standard behind the EAA is EN 301 549, which for software relies on the WCAG 2.1 level AA criteria. The catch: WCAG is written with the web in mind, and translating it to a native iOS app — UIKit or SwiftUI — is precisely the part almost nobody documents.

This checklist does that translation. It is 27 verifiable points, organised into six blocks, each with its WCAG criterion where one applies and a hint at the iOS API involved. Use it to self-assess your app before commissioning an audit, or as a control list during development.

Published: · Updated:
AtalayaSoft iOS developer coding at his desk, with code on screen

How to use this checklist

Every point is a statement your app either meets or does not; there is deliberately no middle ground. Walk through the six blocks with the app in hand, VoiceOver on and text size at maximum. Anything that fails is a real finding an auditor — or a user — will also hit.

This checklist covers what can be verified without real users. It does not replace a full audit: context-dependent criteria, testing with assistive-technology users and the accessibility statement fall outside it — and we explain why at the end of the page.

Summary: checklist blocks, WCAG 2.1 AA criteria involved and related iOS APIs
Block WCAG criteria iOS APIs involved
VoiceOver and semantic labelling 1.1.1 · 1.3.2 · 4.1.2 · 4.1.3 accessibilityLabel, accessibilityTraits, UIAccessibility.post
Text and Dynamic Type 1.4.4 · 1.4.5 preferredFont(forTextStyle:), dynamicTypeSize
Colour and contrast 1.4.1 · 1.4.3 · 1.4.11 Asset Catalog (contrast variants), accessibilityContrast (UIKit) / colorSchemeContrast (SwiftUI)
Touch interaction and gestures 1.3.4 · 2.1.1 · 2.4.7 · 2.5.1 · 2.5.4 accessibilityCustomActions, Full Keyboard Access, focusable()
Forms and transactional flows 1.3.5 · 2.2.1 · 3.3.1 · 3.3.2 · 3.3.3 textContentType, keyboardType, error announcements
Media, motion and dynamic content 1.2.2 · 1.2.5 · 2.3.1 · 2.3.3 AVPlayer (captions), isReduceMotionEnabled

VoiceOver and semantic labelling

VoiceOver is the iOS screen reader and the first filter in any audit. If an element is unlabelled, carries the wrong role or reads in a nonsensical order, the app is unusable for a blind person — no matter how polished everything else is.

  • Every interactive element exposes a concise, descriptive accessibility label; no functional image is announced as just "image" or by its asset name. (WCAG 1.1.1) accessibilityLabel in UIKit; .accessibilityLabel(_:) in SwiftUI. Decorative images are hidden with isAccessibilityElement = false / .accessibilityHidden(true).
  • Every element announces its true role and state: buttons announce as buttons, selected things as selected, disabled things as dimmed. (WCAG 4.1.2) accessibilityTraits (.button, .selected, .notEnabled); .accessibilityAddTraits(_:) in SwiftUI.
  • The VoiceOver reading order follows the visual and functional logic of the screen, not the accidental order of the view hierarchy. (WCAG 1.3.2) accessibilityElements on the container; .accessibilitySortPriority(_:) in SwiftUI.
  • Elements that form one unit of meaning (a cell's icon + title + subtitle) are grouped and read as a single element, not three separate stops. shouldGroupAccessibilityChildren / container element with a composed label; .accessibilityElement(children: .combine) in SwiftUI.
  • Dynamic content changes (loaded results, errors, on-screen updates) are announced to VoiceOver without the user having to hunt for them. (WCAG 4.1.3) UIAccessibility.post(notification: .announcement, …) / .layoutChanged; AccessibilityNotification.Announcement in SwiftUI.
  • Actions available through contextual gestures (swipe to delete, long press) are also exposed to the rotor as custom actions. accessibilityCustomActions; .accessibilityAction(named:) in SwiftUI.

Text and Dynamic Type

Dynamic Type lets users choose their text size system-wide. An app that ignores it — or breaks when it is enabled — excludes a huge share of its users, and it is among the first things any auditor checks because it takes seconds to detect.

  • All text in the app scales with Dynamic Type; there are no fixed font sizes on content screens. (WCAG 1.4.4) UIFont.preferredFont(forTextStyle:) + adjustsFontForContentSizeCategory = true; SwiftUI's Font styles (.body, .headline…) scale by default.
  • No informational text is rasterised inside images; all text is real text that scales and that VoiceOver can read. (WCAG 1.4.5) compose text + image in the view instead of shipping assets with baked-in text.
  • With text enlarged, layouts grow instead of breaking: nothing truncates with "…" losing information, nothing overlaps, and cell heights are self-sizing. Auto Layout without fixed heights, UITableView.automaticDimension; in SwiftUI, avoid restrictive .lineLimit and rigid frames.
  • The app remains functional at the accessibility sizes (AX1–AX5), not just the five standard ones; where a horizontal layout stops fitting, it reflows vertically. traitCollection.preferredContentSizeCategory.isAccessibilityCategory; @Environment(\.dynamicTypeSize) and ViewThatFits in SwiftUI.

Colour and contrast

Insufficient contrast is the most common failure and the cheapest to fix. And colour can never be the sole carrier of meaning: what reads as "red = error" to you is simply another grey to someone with colour blindness.

  • Normal text reaches a minimum contrast of 4.5:1 against its background, and large text and UI components reach at least 3:1 — in dark mode too. (WCAG 1.4.3 · 1.4.11) system semantic colours or Asset Catalog with light/dark variants; verify with Xcode's Accessibility Inspector.
  • No state or information is conveyed by colour alone: errors, selection and active states also carry an icon, text or shape change. (WCAG 1.4.1) design review; SF Symbols as non-colour reinforcement.
  • The app responds to the system contrast settings and does not break under Smart Invert: photos and already-dark content are not inverted. high-contrast variants in the Asset Catalog, UIAccessibility.isDarkerSystemColorsEnabled or traitCollection.accessibilityContrast in UIKit; accessibilityIgnoresInvertColors and @Environment(\.colorSchemeContrast) in SwiftUI.

Touch interaction and gestures

A control existing does not mean it can be used. Tiny touch targets, gestures that demand two hands or surgical precision, and screens that only respond to shaking the phone are direct barriers for people with reduced mobility.

  • Every touch target measures at least 44×44 points, even when its visual representation is smaller. extend the area with insets; in UIKit, override point(inside:with:) or hitTest(_:with:) if needed; Apple's HIG as the reference.
  • Every function triggered by a complex or multipoint gesture (pinch, drag, two-finger swipe) has a single-tap alternative. (WCAG 2.5.1) visible alternative buttons or accessibilityCustomActions.
  • No function depends on moving the device (shake, tilt) without an on-screen alternative, and motion responses can be disabled. (WCAG 2.5.4) UI alternative to CMMotionManager / the shake gesture; honour the system settings.
  • The app is fully operable with Full Keyboard Access and Switch Control: everything interactive receives focus, focus is visible, and there are no focus traps. (WCAG 2.1.1 · 2.4.7) test with Full Keyboard Access on; UIKeyCommand, canBecomeFocused; .focusable() and @FocusState in SwiftUI.
  • The app works in both portrait and landscape; it does not lock to a single orientation unless that is essential to the task (capturing a cheque, for example). (WCAG 1.3.4) do not restrict supportedInterfaceOrientations without justification; in SwiftUI, layouts that adapt to the available size rather than assuming one orientation.

Forms and transactional flows

The EAA is above all about services users do things with: buying, contracting, paying, booking. A flawless onboarding is worth little if the payment form is impassable with VoiceOver. This block decides whether your app complies where it actually matters.

  • Every field has a visible, persistent label; the placeholder is never the only label, because it disappears the moment the user types. (WCAG 3.3.2) visible associated label + accessibilityLabel on the field; in SwiftUI, TextField with LabeledContent or an explicit label.
  • When validation fails, the error is identified and described in text next to the affected field, and VoiceOver announces it at that moment. (WCAG 3.3.1) error message as text tied to the field + UIAccessibility.post(notification: .announcement, …).
  • Recoverable errors offer a concrete correction suggestion ("the IBAN must have 24 characters"), not a generic "invalid data". (WCAG 3.3.3) rule-specific validation messages.
  • Every field declares its purpose and its keyboard: email brings up the email keyboard and autofills, the SMS code suggests itself, passwords work with password managers. (WCAG 1.3.5) textContentType (.emailAddress, .oneTimeCode, .password…) + keyboardType.
  • No step of the transactional flow times out without warning and a way to extend it, and the entire flow — cart to confirmation — is operable end to end with VoiceOver alone. (WCAG 2.2.1) warnings before session expiry with an extend option; manual end-to-end VoiceOver test of the whole flow.

Media, motion and dynamic content

Audiovisual content and animation have rules of their own: what cannot be heard needs captions, what cannot be seen needs description, and motion that looks elegant to you can — literally — make some of your users sick.

  • All pre-recorded video content with audio offers captions, and the player honours the system's caption and styling settings. (WCAG 1.2.2) caption tracks in the asset; AVPlayer handles them with the user's settings (MACaptionAppearance).
  • Pre-recorded video with audio offers audio description wherever visual information is not already carried by the soundtrack; at level AA a transcript does not replace audio description. (WCAG 1.2.5) audio description track in the asset (AVMediaCharacteristic.describesVideoForAccessibility); an accessible transcript is a complement, not the substitute.
  • The app honours the "Reduce Motion" setting: parallax, zooms and large transitions are replaced with fades or removed. (WCAG 2.3.3) Recommended UIAccessibility.isReduceMotionEnabled; @Environment(\.accessibilityReduceMotion) in SwiftUI.
  • Nothing in the app flashes more than three times per second — including videos, loading animations and promotional effects. (WCAG 2.3.1) review of animations and content; no specific API — this is a design rule.

What this checklist does not cover (and when you need an audit)

Being honest here is part of the job: passing these 27 points means you have removed the most frequent, objective barriers — not that your app "complies with the EAA". There are three things a checklist cannot give you:

  • Testing with real assistive-technology users — a reading order can be technically correct and still be exhausting to use; only someone who navigates with VoiceOver daily will reveal that.
  • The criteria that depend on your app's context — what "large text" means in your design, which alternative makes sense for your gesture, which flows are services covered by the EAA and which are not.
  • The formal side of compliance — the documented assessment against EN 301 549 and the accessibility information the service must make publicly available.

Does your app pass the checklist… or not quite?

We run accessibility audits built specifically for native iOS — not web audits adapted after the fact — with remediation included if you need it. From an initial diagnosis to ongoing support, with published pricing.

See the iOS Accessibility (EAA) service

Frequently asked questions

No. The Accessibility Inspector catches a share of the objective problems — missing labels, contrast, touch areas — but it cannot judge whether the reading order makes sense, whether dynamic announcements arrive when they should, or whether the payment flow can be completed with VoiceOver. It is a great development tool and a terrible compliance certificate.

The EAA regulates products and services offered to consumers, so a purely internal app generally falls outside its scope. Two caveats: if end customers use the app at any point, it is in; and workplace accessibility and equal-treatment obligations exist through other legal routes even where the EAA does not apply.

On every release that touches the interface, as part of normal QA — accessibility breaks like any other feature, and refactoring one screen can silently undo labels and groupings. At minimum, a full pass per major iOS version: things change every September.

No: the EAA and EN 301 549 are technology-neutral; what is required is the outcome. What changes is the how: SwiftUI ships better defaults (Dynamic Type, roles), but neither framework complies on its own, and real apps usually mix both — which means verifying that the VoiceOver experience stays coherent when crossing from one world to the other.
Shall we talk?

Let's talk about your iOS challenge

Book 30 minutes with Francisco José García Navarro, Senior iOS Architect, to review your project. No obligation.