Skip to content

fix(ios): improve VoiceOver reading order for ColumnSet elements#653

Open
hggzm wants to merge 1 commit intomicrosoft:mainfrom
hggzm:clean/fix-columnset-reading-order-42
Open

fix(ios): improve VoiceOver reading order for ColumnSet elements#653
hggzm wants to merge 1 commit intomicrosoft:mainfrom
hggzm:clean/fix-columnset-reading-order-42

Conversation

@hggzm
Copy link
Copy Markdown
Collaborator

@hggzm hggzm commented Mar 18, 2026

Fork-based PR (no Azure Pipelines CI). When ready for CI, push branch to upstream as users/hggzm/clean/fix-columnset-reading-order-42 and recreate.

History: upstream PRs #622 (closed)

Summary

VoiceOver was traversing ColumnSet content column-by-column instead of row-by-row. For example, in a flight passenger list with (Name, Seat) columns, VoiceOver would read all names first, then all seat numbers, rather than reading each passenger's name followed by their seat.

This happened because accessibilityElements was set to the column views themselves (via getArrangedSubviews), causing VoiceOver to drill into each column sequentially.

Changes

  • ACRColumnSetRenderer.mm: Instead of setting accessibility elements to the column views, flatten all children from all columns into a single array. VoiceOver then uses geometric frame ordering on these flat elements, naturally producing left-to-right, top-to-bottom (row-by-row) reading order.

Before

VoiceOver reads: "Sarah Hum" → "Jeremy Goldberg" → "Evan Litvak" → "14A" → "14B" → "14C"

After

VoiceOver reads: "Sarah Hum" → "14A" → "Jeremy Goldberg" → "14B" → "Evan Litvak" → "14C"

Testing

  1. Open a card with a ColumnSet that has multiple columns with corresponding rows (e.g. FlightUpdate.json with passenger names and seat numbers)
  2. Enable VoiceOver
  3. Swipe through the ColumnSet content
  4. Verify elements are read row-by-row (left-to-right across columns at each level) rather than column-by-column

VoiceOver was traversing ColumnSet content column-by-column (all items
in column 1, then all items in column 2), instead of row-by-row
(column 1 row 1, column 2 row 1, column 1 row 2, etc.).

This happened because accessibilityElements was set to the column views
themselves, causing VoiceOver to drill into each column sequentially.

Now flattens the children of all columns into a single array, allowing
VoiceOver to use geometric frame ordering (left-to-right, top-to-bottom)
which naturally produces row-by-row reading order.

Fixes #42, #44
@hggzm
Copy link
Copy Markdown
Collaborator Author

hggzm commented Mar 20, 2026

VoiceOver Accessibility Validation

Automated a11y pipeline validates this fix using real UIAccessibility API data.

Annotated A11y Overlay

Annotated screenshot

  • 87 total accessible elements captured from rendered cards via XCUIElement queries
  • accessibilityLabel, accessibilityValue, accessibilityFrame, accessibilityTraits verified
  • Green numbered overlay boxes show exact VoiceOver focus rectangles
  • Element data matches what VoiceOver reads at runtime

Full transcript | Gallery

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant