eps1lon/dom-accessibility-api

computeAccessibleName ignores text inside of shadow DOM

Opened this issue ยท 4 comments

Thank you for writing this library! It's great to see a battle-tested solution for computing accessible names and descriptions. ๐Ÿ™‚

I noticed, though, that when text is inside of the shadow DOM, it appears that computeAccessibleName ignores this text. Here is a CodePen to demonstrate.

Note that the Chrome Accessibility DevTools show the text inside of the shadow root as well as the text outside of the shadow root, since the browser uses both to compute the accessible name:

Screen Shot 2021-10-26 at 9 15 34 AM

In the case of open shadow roots (the most common kind), it should be possible to traverse shadow boundaries and collect the text inside of shadow roots.

Thanks for the report.

This makes sense to me intuitively but it's not very clear from the ACCNAME spec.

Though this may just be an implementation choice or concern for aria-html i.e. is the shadow tree part of the "textual content" and not just textContent? Or should "each child" include traversing the shadow tree?

So while this is trivial to fix for this particular issue, I have no idea how this interacts with more complex shadow trees. Seems like this is still of an open issue in ACCNAME (w3c/accname#51 and w3c/accname#20).

I would appreciate it if somebody could find out how the shadow DOM fits into into story because the usual DOM APIs for text content or children do exclude it by default.

It's unfortunate that the accname spec isn't very clear on this. Based on how screen readers actually behave with shadow content, my intuition is that essentially the shadow tree should be traversed in normal tree order (with slots serialized in the order expressed in the shadow DOM, not light DOM). This aligns with their visual presentation as well.

Based on how screen readers actually behave with shadow content, my intuition is that essentially the shadow tree should be traversed in normal tree order (with slots serialized in the order expressed in the shadow DOM, not light DOM). This aligns with their visual presentation as well.

Would definitely agree here. I think for now we could just walk the shadow tree for textual content and only consider textContent. The goal of this library isn't to match any specific devtools behavior or specific screenr reader behavior but matching existing specifications.

If there are some confirmed reports for at least two screen readers we can consider reading the textual content of the shadow tree. But I'm not comfortable fully applying all semantics to the shadow tree (e.g aria-labelledby). Just concatenating the text content of the shadow tree probably covers most usages of the shadow DOM.

I've found a related issue (repro) that may be slightly easier to fix. If two elements are co-located in the same shadow root, and one references the other with e.g. aria-labelledby, then the accessible name is not computed correctly, due to this line using the ownerDocument rather than the shadow root for getElementById:

.map((id) => node.ownerDocument.getElementById(id))

(node.ownerDocument.getElementById does not work, because the element with the ID is inside of the shadow root. But node.getRootNode().getElementById would work.)

If there are some confirmed reports for at least two screen readers we can consider reading the textual content of the shadow tree.

If you test the two demos I provided (here's the other one), you should see that both NVDA on Windows (Firefox and Chrome) and VoiceOver on MacOS (Safari, Chrome, and Firefox) read the button text contents, even the content inside of the shadow root. Ditto for the label+input in the above demo. I'm not sure if it's explicitly specified by the spec, but those screen readers at least (I haven't tested others) can read content inside the shadow DOM.