Skip to content

Reveal in-bounds elements covered by floating overlays before failing tappability - #1345

Merged
RoyalPineapple merged 2 commits into
masterfrom
reveal-covered-elements
Jul 24, 2026
Merged

Reveal in-bounds elements covered by floating overlays before failing tappability#1345
RoyalPineapple merged 2 commits into
masterfrom
reveal-covered-elements

Conversation

@RoyalPineapple

@RoyalPineapple RoyalPineapple commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Problem

A tap target can sit fully inside its scroll view's visible rect and still be un-tappable because a floating overlay (tab bar, toolbar) hovers over it. +viewContainingAccessibilityElement:tappable:error:disableScroll: never recovers from this:

  1. The scroll pass only scrolls when the element is outside the visible rect (CGRectContainsRect(visibleRect, elementFrame)), so an in-bounds element is left exactly where it is.
  2. The hit test then resolves to the overlay instead of the element, and the method fails with is not tappable. It may be blocked by other views.

Any list whose last rows extend under a floating bar hits this. In our suite this had already been worked around the only way possible: robot code that detects the failed hit test, walks up to the scroll ancestor, and sets contentOffset by hand.

Change

When the tappability check fails and scrolling is allowed, center the element vertically in its nearest scroll ancestor's adjustedContentInset-adjusted viewport, then resolve once more with disableScroll:YES. Overlays that cause this failure are anchored to the viewport's edges, so centering moves the element out from under them.

Safety

  • The new path runs only where the method currently returns an error — no passing interaction changes behavior. The existing scroll pass, table-cell handling, and visible-rect fast path are untouched.
  • Genuinely blocked elements still fail with the same error: if there is no scroll ancestor, the viewport has no height, or the element is already as centered as the content allows, scrolling can't uncover it and the method returns the original failure.
  • One re-resolution, no loops; callers' outer wait loops retry as they do today.
  • The scroll honors testActorAnimationsEnabled and uses the same settle delays (KIFRunLoopRunInModeRelativeToAnimationSpeed, 0.3s/0.05s) as the existing scroll pass.

Testing

Validated against a production suite of several hundred KIF integration tests. Rows covered by a floating tab bar on phone-size devices now pass with their hand-rolled scroll workarounds deleted, and no previously-passing test changed behavior. (The same logic ran there first as a swizzle wrapping this method; this PR contributes it natively.)

… tappability

viewContainingAccessibilityElement:tappable:error:disableScroll: only
auto-scrolls when the element's frame lies outside its scroll view's
visible rect. An element that is inside the visible rect but occluded
by a floating overlay (a tab bar or toolbar hovering over the last rows
of a scroll view) skips that scroll and hard-fails the tappability
check with "may be blocked by other views".

When the tappability check fails and scrolling is allowed, center the
element vertically in its nearest scroll ancestor's inset-adjusted
viewport, which moves it clear of edge-anchored overlays, then resolve
once more with scrolling disabled. If the element is already as
centered as the content allows, scrolling cannot uncover it, so the
original error is preserved for genuinely blocked elements.
@RoyalPineapple
RoyalPineapple marked this pull request as ready for review July 24, 2026 12:16
A scroll view acting as the accessibility container resolves as the
element's containing view, so the reveal search must start at the view
rather than its superview, matching the existing scroll pass.
@RoyalPineapple
RoyalPineapple merged commit a1661bb into master Jul 24, 2026
3 checks passed
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.

2 participants