-
Notifications
You must be signed in to change notification settings - Fork 60
Description
Background: @nolanlawson proposed on #192 that IDL attributes be allowed to refer into open shadow roots (through arbitrarily many layers of open shadow roots, as long as no closed shadow roots were involved). It was noted during that discussion that as currently specified, setting an IDL attribute to an element does have an effect, except the effect is only to set some data internal to the browser that can't be observed unless the DOM structure changes - trying to read back the IDL attribute simply returns null, as if no value had been set, and nothing is exposed to AT. The question was raised whether it might be possible to expose that data to assistive technology even though it wasn't exposed to the DOM API - so encapsulation might be preserved, but setting the attribute still have an observable (via AT/developer tools only) effect. This was dismissed as having developer ergonomics which were too bad to be workable. There was also concern around the idea of treating open shadow roots and closed shadow roots differently in this context.
Proposal:
I'd like to iterate on Nolan's proposal by proposing that
- we allow references into open (and possibly even closed?) shadow roots, but preserve encapsulation by retargeting the element returned from the IDL attribute getter, the way we do for event targeting.
- we provide an API to allow "undoing" the retargeting, to the extent that the caller already has access to each relevant shadow root. This API would allow authors to debug and test code which refers into shadow roots.
For example,
<!-- wants to refer into custom-optionlist's shadow root -->
<input role="combobox" id="input"
aria-owns="optlist"
aria-activedescendant> <!-- aria-activedescendant set via IDL attribute -->
<custom-optionlist id="optlist">
#shadowRoot
| <x-option id="opt1">221B Baker St</x-option>
| <x-option id="opt2">29 Acacia Road</x-option>
| <x-option id="opt3">724 Evergreen Terrace</x-option>
#/shadowRoot
</custom-optionlist>input.ariaActiveDescendantElement = opt1;
console.log(input.ariaActiveDescendantElement); // logs <custom-optionlist id="optlist">
let deepActiveDescendant =
input.getAttrAssociatedElement("aria-activedescendant",
{shadowRoots: [optlist.shadowRoot]});
console.log(deepActiveDescendant); // logs <x-option id="opt1">221B Baker St</x-option>This preserves encapsulation by requiring an explicit step (and access to the shadow root) to access elements inside shadow roots.
This proposal is inspired by several precedents:
getComposedRanges(shadowRoots)in the Selection API, which takes a list of known shadow roots and "enables the method to return Nodes within the provided list of shadow roots, if necessary."Event.composedPath()which returns the objects an event will be fired on during propagation, including any nodes in the event path which are inside open shadow roots, but no closed shadow roots. (@annevk has noted that "that was more of a compromise than a desired design path," in the context of the discussion which led togetComposedRanges().)- Event target retargeting itself.
Document.activeElementwhich also performs retargeting in its getter.