You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
toSemanticEvents(respectAccessibility = true) skips subtrees excluded from the accessibility tree by aria-hidden="true", display:none, and visibility:hidden (isAccessibilityHidden). Chrome's tree drops more than that: empty inline wrappers, hidden-attribute elements, elements with no accessible content, some content clipped/positioned offscreen specifically for assistive tech. A node Chrome ignores and that carries no text is safe to drop, removing structural noise the current capture keeps.
Depends on #48 (shared introspection layer). Lowest priority of the accessibility set — hold until a real capture demonstrates the noise; do not implement speculatively.
Signal
An element is ignored by the accessibility tree roughly when its computed role resolves to nothing renderable AND it contributes no name/text. Detection options:
computedRole == "" (present-but-roleless / ignored) combined with an empty computedName and no descendant text. The combination is essential — see the trap.
The hidden attribute and inert are cheap explicit signals not currently checked by isAccessibilityHidden; those can be added independently of the flag.
⚠️ The trap
This is the most dangerous of the accessibility issues because "ignored" is easy to over-apply:
computedRole == "" also describes a layout-table node (the shipped layout-table case) and presentation nodes (Generalize role=presentation/none unwrapping beyond tables #50) whose children are meaningful — those must be unwrapped, not skipped. Skipping would delete content.
Offscreen "visually-hidden but screen-reader-visible" patterns (.sr-only) are the OPPOSITE — present in the tree, must be kept.
So the rule must be ignored AND empty (no text, no accessible name, no meaningful descendants) → skip; never "ignored" alone. The classifier ordering from #48 matters: unwrap/rename cases must be evaluated before the skip case.
Suggested approach
Add a Skip case to the #48 classifier, gated on the conjunction above, evaluated after the unwrap/rename cases. Start conservative: only hidden/inert attributes + truly empty roleless nodes. Expand the net only against evidence from rendered-Markdown diffs on real dumps (./gradlew :markanywhere-html:renderDumpMarkdown).
Test approach
Deterministic, under ChromeHeadlessExperimentalA11y:
<span></span> between content → dropped, surrounding text intact.
<div hidden>secret</div> → dropped.
Negative / safety:<div class="sr-only">screen reader text</div> (offscreen but in the tree) → KEPT.
Negative / safety: a roleless wrapper with text children → children survive (not skipped).
Out of scope
Anything that moves or reorders content (aria-owns).
Re-deciding the existing aria-hidden/display:none/visibility:hidden behaviour, which already works.
Summary
toSemanticEvents(respectAccessibility = true)skips subtrees excluded from the accessibility tree byaria-hidden="true",display:none, andvisibility:hidden(isAccessibilityHidden). Chrome's tree drops more than that: empty inline wrappers,hidden-attribute elements, elements with no accessible content, some content clipped/positioned offscreen specifically for assistive tech. A node Chrome ignores and that carries no text is safe to drop, removing structural noise the current capture keeps.Depends on #48 (shared introspection layer). Lowest priority of the accessibility set — hold until a real capture demonstrates the noise; do not implement speculatively.
Signal
An element is ignored by the accessibility tree roughly when its computed role resolves to nothing renderable AND it contributes no name/text. Detection options:
computedRole == ""(present-but-roleless / ignored) combined with an emptycomputedNameand no descendant text. The combination is essential — see the trap.hiddenattribute andinertare cheap explicit signals not currently checked byisAccessibilityHidden; those can be added independently of the flag.This is the most dangerous of the accessibility issues because "ignored" is easy to over-apply:
computedRole == ""also describes a layout-table node (the shipped layout-table case) and presentation nodes (Generalize role=presentation/none unwrapping beyond tables #50) whose children are meaningful — those must be unwrapped, not skipped. Skipping would delete content..sr-only) are the OPPOSITE — present in the tree, must be kept.So the rule must be ignored AND empty (no text, no accessible name, no meaningful descendants) → skip; never "ignored" alone. The classifier ordering from #48 matters: unwrap/rename cases must be evaluated before the skip case.
Suggested approach
Add a
Skipcase to the #48 classifier, gated on the conjunction above, evaluated after the unwrap/rename cases. Start conservative: onlyhidden/inertattributes + truly empty roleless nodes. Expand the net only against evidence from rendered-Markdown diffs on real dumps (./gradlew :markanywhere-html:renderDumpMarkdown).Test approach
Deterministic, under
ChromeHeadlessExperimentalA11y:<span></span>between content → dropped, surrounding text intact.<div hidden>secret</div>→ dropped.<div class="sr-only">screen reader text</div>(offscreen but in the tree) → KEPT.Out of scope
aria-owns).aria-hidden/display:none/visibility:hiddenbehaviour, which already works.