3.6 — Accessibility in design

Opening scenario

Apple’s App Store editorial team reviews your app for a feature spot. They turn on VoiceOver. Nothing reads. They turn up text size. Buttons overflow. They check tap targets — your icons are 24×24. You don’t get featured.

Then a class-action ADA lawsuit gets filed against your industry vertical. Apps without basic accessibility are getting sued in the US, the EU, and Brazil. The cost of not shipping accessibility is now larger than the cost of shipping it.

This chapter teaches the design-side accessibility rules: contrast ratios, tap target sizes, VoiceOver annotations, and the handoff between designer and engineer.

StandardSourceEnforced by
WCAG 2.1 AAW3CLawsuits (ADA, EAA), Apple A11y team
Apple HIG accessibilityAppleApp Review, feature curation
44×44pt minimum tap targetHIGUX & lawsuit risk
4.5:1 contrast (normal text)WCAG 2.1 AASame
3:1 contrast (large text 18pt+ or 14pt+ bold)WCAG 2.1 AASame

Concept → Why → How → Code

Contrast ratios — the math you don’t have to do

WCAG defines contrast as the ratio between foreground and background luminance. The thresholds:

Text typeMinimum AAMinimum AAA
Normal text (<18pt or <14pt bold)4.5:17:1
Large text3:14.5:1
UI components (icons, borders)3:1

Tools to check:

  • Contrast by Sam Soffes — Mac app, free; menu bar utility, pick two pixels, get ratio
  • Stark — Figma plugin, audits your whole file
  • Accessibility Inspector — built into Xcode, runs on a live simulator
  • Web: WebAIM Contrast Checker

The fast workflow: in Figma, install Stark; in Xcode dev, use Accessibility Inspector → Audit. Both catch the same problems pre-merge.

Minimum tap target — 44×44pt

Apple’s hard rule: any interactive element must have a tap target of at least 44×44pt. The visual size can be smaller (a 24×24pt icon is fine), but the tappable area must extend to 44×44.

// ❌ Visually small AND tap-area small — fails 44pt minimum
Image(systemName: "xmark")
    .onTapGesture { dismiss() }

// ✅ Visual 24pt, tap area 44pt
Button { dismiss() } label: {
    Image(systemName: "xmark")
        .imageScale(.medium)
}
.frame(width: 44, height: 44)

// ✅ Even simpler: use .contentShape() to expand hitbox without changing layout
Image(systemName: "xmark")
    .frame(width: 44, height: 44)
    .contentShape(Rectangle())
    .onTapGesture { dismiss() }

In Figma, designers should always show a transparent 44×44pt hit-target rectangle around small icons during dev-handoff. If they don’t, flag it in PR review with a screenshot of HIG’s accessibility section.

Touch target spacing

Two tap targets need at least 8pt of space between them (often 16pt is better). Stacked buttons that share a border violate this — users fat-finger the wrong one.

VoiceOver — what designers need to spec

VoiceOver reads the screen aloud, navigated by swipe-right/swipe-left to walk through elements. Each interactive or informational element must have:

  1. Label — what the element is (“Like button,” “Profile photo of Alex,” “5 unread messages”)
  2. Trait — its role (button, link, header, image, adjustable)
  3. Value (for adjustable elements) — current state (“3 of 5 stars”)
  4. Hint (optional) — what tapping it does (“Opens user profile”)

In SwiftUI:

Image(systemName: "heart.fill")
    .accessibilityLabel("Like")
    .accessibilityAddTraits(.isButton)
    .accessibilityHint("Likes this post")

// For toggles/sliders
Toggle("Notifications", isOn: $enabled)
    .accessibilityValue(enabled ? "On" : "Off")  // SwiftUI does this automatically for Toggle

// Decorative-only (e.g. background pattern)
Image("backgroundPattern")
    .accessibilityHidden(true)

The designer’s job: annotate the Figma file with VoiceOver labels for every screen. Use Figma comments or a dedicated “A11y” page with the screen + label callouts. Without these annotations, engineers guess — and often guess wrong.

Annotation layers in Figma

Best-practice Figma file structure for accessibility:

Page: "Feed Screen"
  Frame: ✅ Ready for dev
    [your design]
  Frame: A11y annotations
    [same design with red callouts: "Label: 'Profile photo of Alex'", "Trait: button"]

The annotation page is the engineer’s spec. Designers using Stark or the A11y Annotations plugin generate these in seconds.

Reading order

VoiceOver walks elements in visual order by default — left-to-right, top-to-bottom. When you have a custom layout that breaks this (e.g. a floating action button positioned mid-screen), explicitly set order:

.accessibilitySortPriority(1)  // higher = read first

Or for an entire view group, override the order:

VStack {
    Text("Title")
    Image("hero")
    Text("Body")
}
.accessibilityElement(children: .combine)
// → reads as one continuous element instead of three

Common accessibility design mistakes

  1. Color-only state indicators: “the red dot means unread.” A colorblind user (~8% of men, ~0.5% of women) can’t see red vs gray. Add a glyph or label.
  2. Placeholder-only labels: a text field with placeholder “Email” and no label disappears once the user types. Use TextField("Email", text:) with proper label.
  3. Tiny disabled states: a disabled button at 20% opacity may fail 3:1 contrast. WCAG actually exempts disabled controls — but if it’s the only path forward in the UX, this UX is broken.
  4. Auto-playing audio/video with no controls: WCAG violation; Apple actively rejects.
  5. Fixed-size text (covered in 3.5).
  6. Animations triggered without user input that can’t be disabled (covered in 3.5 via Reduce Motion).

The Accessibility Inspector

Built into Xcode. Run your app in Simulator, then in Xcode menu: Open Developer Tool → Accessibility Inspector.

Three tabs:

  • Inspect: hover any pixel; see the element, its label, trait, value
  • Audit: runs a checklist (contrast, tap target size, missing labels) on the entire screen — use this before every PR
  • Settings: simulate VoiceOver, Increased Contrast, Reduced Transparency from your Mac

The Audit tool is the single highest-ROI accessibility tool. Run it. Fix what it flags. Re-run.

In the wild

  • Apple’s own Accessibility team maintains a WWDC session library — start with “Catalog accessible apps” (WWDC23) and “Build accessible apps with SwiftUI and UIKit” (WWDC22).
  • Apple Maps has a dedicated VoiceOver mode that announces turn-by-turn with cardinal directions, gates, and obstacles. Best-in-class implementation.
  • Twitter was sued in 2020 for not labeling images in tweets; result was the image-description field. Lawsuit-driven accessibility is real.
  • Domino’s Pizza lost a US Supreme Court case in 2019 because its app wasn’t accessible (Robles v. Domino’s Pizza). Set legal precedent that ADA covers iOS apps.
  • Stark is the de facto Figma accessibility plugin — used at Microsoft, Shopify, Airbnb. Worth the $12/mo team fee.

Common misconceptions

  1. “Accessibility is for blind users.” No. VoiceOver users are ~1-2% of iOS. Dynamic Type users are 30%+. Reduced Motion is 5-10%. Captioning helps deaf and language learners. Accessibility = inclusive design.
  2. “Accessibility is the engineer’s job.” It starts with the designer. If contrast fails in Figma, no amount of engineering rescues it.
  3. “AAA is the gold standard; we should aim for it.” AAA is borderline impossible (7:1 contrast on body text) for branded UIs. AA is the ship target. AAA is for specific accessibility-focused apps.
  4. “VoiceOver labels will sound robotic — designers should care about copy.” They should. Labels are UX copy. “Profile” vs “Profile photo of Alex” — the latter is correct.
  5. “Compliance is enough.” Compliance avoids lawsuits. Excellence comes from designing with disabled users (not just for them). Apple’s accessibility team includes engineers who use these features daily — copy their approach.

Seasoned engineer’s take

Accessibility is the cheapest brand win in iOS. The investment is small (mostly discipline + labels + sane defaults), and the upside includes feature spots, awards, and lawsuit avoidance.

If your team doesn’t budget time for accessibility, just do it anyway as part of the work. Adding .accessibilityLabel("...") to a button takes 10 seconds. It will not show up on velocity metrics but it will show up in the Audit Inspector being green and your reviewers being happy.

The Friday ritual: open your app with VoiceOver on. Try to use the new feature without looking at the screen. If you can’t complete the task, your users can’t either. (You’ll be horrified the first time. That’s normal.)

TIP: Add --accessibility-audit-fail to your XCUITest CI step (iOS 17+ XCUIApplication has performAccessibilityAudit() that throws on failure). Cheap CI gate.

WARNING: Don’t ship accessibilityLabel("") (empty) to “hide” an element — use .accessibilityHidden(true). Empty label reads as “blank, button” which is worse than no label.

Interview corner

Junior-level: “What’s the minimum tap target size on iOS?”

44×44pt per Apple HIG. Visual size can be smaller, but the tappable area must extend to 44×44 via .frame() and .contentShape().

Mid-level: “How do you make a SwiftUI screen accessible?”

Every interactive element gets .accessibilityLabel; decorative-only get .accessibilityHidden(true); groups that should read as one use .accessibilityElement(children: .combine). Test with Accessibility Inspector Audit; verify Dynamic Type up to AX3; check contrast ≥ 4.5:1 for text. Use VoiceOver in Simulator to walk through.

Senior-level: “How would you enforce accessibility standards across a 50-person iOS team?”

(1) Designers run Stark in Figma; failed designs get returned. (2) Engineers run Accessibility Inspector Audit pre-PR; CI runs XCUIApplication performAccessibilityAudit() and fails on regressions. (3) Custom SwiftLint rule banning Color(red:) and bare Image() without accessibilityLabel. (4) Quarterly accessibility audit with disabled users (paid, real users — there are agencies for this). (5) Accessibility champion role rotating between engineers. (6) Public commitment in App Store description so the brand stays accountable.

Red flag in candidates: “We’ll add accessibility once we have a designer who knows it.” Means it never ships.

Lab preview

You’ll fix 6 deliberate HIG and accessibility violations in Lab 3.2 — HIG & Accessibility Audit.


Next: 3.7 — Exporting assets from Figma