Reading Order Contract

Status: ready

Intent

The order VoiceOver, Switch Control and the keyboard follow matches the user's task.

Problem

The visual order is clear, but VoiceOver follows the implementation tree. The button is read before the error it fixes. The price comes before the product name. A sheet opens and focus stays behind it.

Solution

Verdict: write the expected order for every critical screen in design review. Get it from code structure first, explicit order second.

Why: a written order gives design, development and QA the same target. Without it, the order is whatever the layout code happens to produce.

Checkout, error state:
1. Screen title
2. Error summary
3. First invalid field
4. Primary action
5. Support link

Implementation

SwiftUI, the code is already in task order. No priorities needed:

VStack(alignment: .leading) {
    Text("Payment").font(.title.bold())
        .accessibilityAddTraits(.isHeader)
    ErrorSummary(errors)
    CardForm()
    Button("Pay") { pay() }
}

SwiftUI, when the layout forces a different visual order. Higher priority is read first, within one container:

VStack {
    Text("Payment failed").accessibilitySortPriority(3)
    TextField("Card number", text: $card).accessibilitySortPriority(2)
    Button("Try again") { pay() }.accessibilitySortPriority(1)
}
.accessibilityElement(children: .contain)

If every element needs a priority, the view structure needs fixing, not more priorities.

UIKit, custom container:

view.accessibilityElements = [
    titleLabel,
    errorLabel,
    cardNumberField,
    payButton,
    supportButton
]

Update the array when elements appear or disappear. An element missing from it can't be reached.

Check

Profile:   VoiceOver
Task:      recover from a failed payment
Expected:  the order matches the written contract
           the error comes before "Try again"
           nothing behind the sheet is reachable
Profile:   VoiceOver, Arabic locale
Task:      the same
Expected:  the same task order, with the visual layout mirrored
Profile:   Switch Control
Task:      scan the form
Expected:  the same order as VoiceOver

Pitfalls

  1. An order that contradicts what the user sees.
  2. Priorities as a patch for a chaotic layout.
  3. Only the happy path written down. Error states and sheets need their own order.
  4. Assuming a ZStack reads front to back.

WCAG mapping

  1. 1.3.2 Meaningful Sequence: the order preserves meaning.
  2. 2.4.3 Focus Order: focus order supports the task.
  3. 3.3.1 Error Identification: the error comes where the user can act on it.
  1. Reading Order Drift
  2. Label Soup
  1. Chapter 3
  2. Chapter 5
  3. Chapter 11
  4. Chapter 12

Sources

  1. Apple Human Interface Guidelines: Accessibility
  2. Apple Developer: accessibilitySortPriority
  3. Apple Developer: accessibilityElements