Repository navigation
Filter non-ItemView subviews out of accessibilityElements - #345
Merged
brynbodayle merged 1 commit intoAug 12, 2026
Merged
Conversation
`CalendarScrollView.accessibilityElements` force-casts every subview to
`[ItemView]` and `fatalError`s if the cast fails. That invariant holds only while
HorizonCalendar is the sole contributor of subviews. On iOS 27 UIKit adds two
`_UITouchPassthroughView`s to the scroll view, so the cast fails and the app
dies:
HorizonCalendar/CalendarScrollView.swift:55: Fatal error:
Only `ItemView`s can be used as subviews of the scroll view.
Filters to the item views instead of requiring that every subview is one. The
views UIKit adds are private hit-testing views with no content, so the resulting
element set matches what the force-cast produced on earlier OS versions.
Only the accessibility path reads this property, so it stays hidden until
something queries accessibility.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jqsilver
marked this pull request as ready for review
August 12, 2026 20:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Details
CalendarScrollView.accessibilityElementsforce-casts every subview to[ItemView], andfatalErrors if the cast fails:That invariant holds only while HorizonCalendar is the sole contributor of subviews. On iOS 27, UIKit adds two
_UITouchPassthroughViews to the scroll view, so the cast fails and the app dies:This filters to the item views instead of requiring that every subview is one:
I left the
fatalErrorin thesortedclosure below alone, since thefilterabove it means it is unreachable.I also considered pairing the filter with an
assertionFailure, to keep a development signal that an unexpected subview showed up. It seemed wrong here: on iOS 27 the unexpected subviews are normal and arrive on every calendar, so the assert would fire constantly while telling developers about something they cannot act on.Related Issue
None filed. Happy to open one if you would prefer to track it separately.
Motivation and Context
This is a crash rather than a cosmetic problem, and because it is a
fatalErrorinside the library, a consumer cannot work around it — there is no way to stop UIKit from adding those subviews, and no way to avoid the property being read.Only the accessibility path reads
accessibilityElements, so it stays hidden until something queries accessibility. It surfaced for us in accessibility snapshot tests on Xcode 27, which took out every calendar-bearing screen we snapshot while everything else stayed green. It should equally affect real users who have Voice Over enabled on iOS 27.The two views UIKit adds are private hit-testing views that carry no content, so filtering them out produces the same element set that the force-cast produced on iOS 26 and earlier. Voice Over behavior is unchanged.
We are running this as a local patch against
470234795d31at Airbnb to unblock our Xcode 27 work.How Has This Been Tested
Added
CalendarScrollViewTests, which adds a plainUIViewalongside anItemViewand asserts that the item view is still returned. It does not depend on UIKit inserting anything, so it reproduces the crash on any OS version. I checked that it does — reverting just the fix and rerunning it on iOS 26 crashes in the test:Ran the full test suite on iOS 26 (
xcodebuild test -destination "name=iPhone 16"), 107 tests green.The test file needed adding to the test target in
HorizonCalendar.xcodeproj, which is the only reason the project file is in this diff.Verified the fix end to end in the Airbnb app under Xcode 27.0 beta 4 on an iOS 27.0 simulator. Before:
Fatal error, and the accessibility snapshot suite executed 0 tests. After: the suite passes and captures its snapshots.Confirmed on iOS 26 that snapshots are byte-identical with and without the change, so this is not a behavior change on shipping OS versions.
Types of changes
Checklist
One note on the CONTRIBUTING checklist: it asks for a version bump in the Xcode project and podspec, and I have not done one. The recent merged PRs (#338, #340, #342) update only the CHANGELOG under
[Unreleased], so I followed that. Glad to add a bump if you want it.Please Review
@bryankeller @brynbodayle @marybm-dev