Repository navigation
Treat untabbable free-text controls under an in-form aria-hidden ancestor as traps and drop their wrapper copy - #3554
Merged
Conversation
…stor as traps and drop their wrapper copy
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.
Summary
An untabbable free-text field was only treated as a trap when
aria-hidden="true"was on the field itself. When the attribute was on a wrapper inside the form (a common honeypot pattern), the trap's label, input and wrapper came out of readable form blocks as acore/htmlblock inside an empty group. Now the field counts as a trap when any ancestor inside its form is aria-hidden, and the trap claims its label and every trap-only container up to that ancestor, so none of its markup reaches readable blocks or the form layout graph.What changed
isUnreachableTextTrapnow also fires when an ancestor of the control isaria-hidden="true". The walk stops at the control's native form, so aria-hidden outside the form does not count. Only free-text entry qualifies, as before; checkbox, radio and select carriers behave as they did.honeypotCopyElementsnow claims the trap's label and every container from the trap up to and including its outermost in-form aria-hidden ancestor. It still never claims a form, a fieldset, or a container that holds a real control.tests/unit/invisible-unreachable-text-trap.phpadds the neutral name/email/message fixture with the aria-hidden off-screen wrapper. ThroughArtifactCompilerit checks that the readable blocks have nocore/html, no "Leave empty" text and no leftover wrapper group, and that the layout graph has no trap markup. It also checks the choice-carrier case and the form boundary.Verification
403ea54. Basetrunk@4f62f31unchanged.Cook run
972fd030f4c4eb4c8fda47ac071bc82fe12ffaf2, fingerprint82c4a467637e1e3c96caff1483f7989581b6ac3087258b1531ba5bffdfd2caeeAI assistance
Tool: Homeboy (pi) · Model: claude-opus-5-5 (tier roadie/cook-heavy) · Used for: The AI read the classifier and its callers, reproduced the leaked
core/htmlblock through the compile path, made the fix, added the regression test (confirmed failing on trunk), and ran the gates.Closes #3550