1. Introduction
Content on the web being accessible is critically important. Maintaining accessibility within web components is challenging as the shadow root encapsulation prevents references between elements in different roots. These references are fundamental to enable assistive technologies within web applications.
Today, a web application can be composed by many web components that are connected through different relationships. ARIA is the appropriate standard to describe those relationships. Unfortunately, it’s not possible to natively connect ARIA attributes from elements belonging to different DOM trees belonging to the main page and one or many web components. Because of that, some complex and not fully successful workarounds need to be applied.
-
Observing and moving ARIA-related attributes across elements (for role, etc.).
-
Using non-standard attributes for ARIA features, in order to apply them to elements in a shadow root.
-
Requiring usage of custom elements to wrap/slot elements so that ARIA attributes can be placed directly on them. This gets very complicated as the number of slotted inputs and levels of shadow root nesting increase.
-
Duplicating nodes across shadow root boundaries.
-
Abandoning Shadow DOM.
1.1. This proposal
This proposal introduces a reflection API to allow for ARIA attributes and properties set on elements in a shadow root to be reflected into the parent DOM tree through their host element.
This mechanism will allow users to apply standard best practices for ARIA and resolve a large margin of accessibility use cases for applications of native Web components and native Shadow DOM. This API is most suited for one-to-one delegation, but should also work for one-to-many scenarios. There is no mechanism for directly relating two elements in different shadowroots together, but this will still be possible manually with the element reflection API.
The proposed extension adds a new `reflects*` (e.g.: `reflectsAriaLabel`, `reflectsAriaDescribedBy`) options to the `.attachShadow` method similarly to the `reflectsFocus`, while introducing a new content attribute `reflect*` (e.g.: `reflectarialabel`, `reflectariadescribedby`) to be used in the shadowroot inner elements. This has an advantage that it works with Declarative Shadow DOM as well, and it is consistent with `reflectsFocus`. Even though, it requires another set of html attributes in the declarative shadow root template. The declarative form works better with common developer paradigm where you may not necessarily have access to a DOM node right where you’re creating / declaring it.
The attributes names such as `shadowrootreflects*` are very long and some consideration for shorter names by removing the `shadowroot` prefix can be discussed as long the discussion is sync’ed with the stakeholders of the respective Declarative Shadow DOM proposal.
2. IDL Interface
Conforming user agents MUST implement the following IDL interface.
2.1. Interface Mixin ReflectARIAMixin
interface mixin {
ReflectARIAMixin attribute DOMString ?;
reflectAriaAtomic attribute DOMString ?;
reflectAriaAutoComplete attribute DOMString ?;
reflectAriaBusy attribute DOMString ?;
reflectAriaChecked attribute DOMString ?;
reflectAriaColCount attribute DOMString ?;
reflectAriaColIndex attribute DOMString ?;
reflectAriaColIndexText attribute DOMString ?;
reflectAriaColSpan attribute DOMString ?;
reflectAriaCurrent attribute DOMString ?;
reflectAriaDescription attribute DOMString ?;
reflectAriaDisabled attribute DOMString ?;
reflectAriaExpanded attribute DOMString ?;
reflectAriaHasPopup attribute DOMString ?;
reflectAriaHidden attribute DOMString ?;
reflectAriaInvalid attribute DOMString ?;
reflectAriaKeyShortcuts attribute DOMString ?;
reflectAriaLabel attribute DOMString ?;
reflectAriaLevel attribute DOMString ?;
reflectAriaLive attribute DOMString ?;
reflectAriaModal attribute DOMString ?;
reflectAriaMultiLine attribute DOMString ?;
reflectAriaMultiSelectable attribute DOMString ?;
reflectAriaOrientation attribute DOMString ?;
reflectAriaPlaceholder attribute DOMString ?;
reflectAriaPosInSet attribute DOMString ?;
reflectAriaPressed attribute DOMString ?;
reflectAriaReadOnly attribute DOMString ?;
reflectAriaRequired attribute DOMString ?;
reflectAriaRoleDescription attribute DOMString ?;
reflectAriaRowCount attribute DOMString ?;
reflectAriaRowIndex attribute DOMString ?;
reflectAriaRowIndexText attribute DOMString ?;
reflectAriaRowSpan attribute DOMString ?;
reflectAriaSelected attribute DOMString ?;
reflectAriaSetSize attribute DOMString ?;
reflectAriaSort attribute DOMString ?;
reflectAriaValueMax attribute DOMString ?;
reflectAriaValueMin attribute DOMString ?;
reflectAriaValueNow attribute DOMString ?; };
reflectAriaValueText
Interfaces that include `ReflectARIAMixin` must provide the following algorithms:
-
`ReflectARIAMixin` getter steps, which take the host interface instance, IDL attribute name, and content attribute name, and must return a string value; and
-
`ReflectARIAMixin` setter steps, which take the host interface instance, IDL attribute name, content attribute name, and string value, and must return nothing.
For every IDL attribute idlAttribute defined in `ReflectARIAMixin`, on getting, it must perform the following steps:
-
Let contentAttribute be the ReflectARIA content attribute determined by looking up idlAttribute in the ReflectARIA Attribute Correspondence table.
-
Return the result of running the `ReflectARIAMixin` getter steps, given this, idlAttribute, and contentAttribute.
Similarly, on setting, it must perform the following steps:
-
Let contentAttribute be the ReflectARIA content attribute determined by looking up idlAttribute in the ReflectARIA Attribute Correspondence table.
-
Run the `ReflectARIAMixin` setter steps, given this, idlAttribute, contentAttribute, and the given value.
2.2. ReflectARIA Attribute Correspondence
The following table provides a correspondence between IDL attribute names and content attribute names, for use by `ReflectARIAMixin`.
2.3. `ReflectARIAMixin` Mixed in to `Element`
User agents MUST include `ReflectARIAMixin` on `Element`:
Element includes ReflectARIAMixin ;
For `Element`:
-
The `ReflectARIAMixin` getter steps given element, idlAttribute, and contentAttribute are to return the result of the getter algorithm for idlAttribute reflecting<contentAttribute on element.
-
The `ReflectARIAMixin` setter steps given element, idlAttribute, contentAttribute, and value are to perform the setter algorithm for idlAttribute reflecting contentAttribute on element, given value.
Note: In practice, this means that, e.g., the `reflectAriaAtomic` IDL on `Element` reflects the `reflectariaatomic` content attribute;
2.4. Interface Mixin ShadowRootMixin
interface mixin {
ShadowRootMixin attribute DOMString ?;
reflectsAriaAtomic attribute DOMString ?;
reflectsAriaAutoComplete attribute DOMString ?;
reflectsAriaBusy attribute DOMString ?;
reflectsAriaChecked attribute DOMString ?;
reflectsAriaColCount attribute DOMString ?;
reflectsAriaColIndex attribute DOMString ?;
reflectsAriaColIndexText attribute DOMString ?;
reflectsAriaColSpan attribute DOMString ?;
reflectsAriaCurrent attribute DOMString ?;
reflectsAriaDescription attribute DOMString ?;
reflectsAriaDisabled attribute DOMString ?;
reflectsAriaExpanded attribute DOMString ?;
reflectsAriaHasPopup attribute DOMString ?;
reflectsAriaHidden attribute DOMString ?;
reflectsAriaInvalid attribute DOMString ?;
reflectsAriaKeyShortcuts attribute DOMString ?;
reflectsAriaLabel attribute DOMString ?;
reflectsAriaLevel attribute DOMString ?;
reflectsAriaLive attribute DOMString ?;
reflectsAriaModal attribute DOMString ?;
reflectsAriaMultiLine attribute DOMString ?;
reflectsAriaMultiSelectable attribute DOMString ?;
reflectsAriaOrientation attribute DOMString ?;
reflectsAriaPlaceholder attribute DOMString ?;
reflectsAriaPosInSet attribute DOMString ?;
reflectsAriaPressed attribute DOMString ?;
reflectsAriaReadOnly attribute DOMString ?;
reflectsAriaRequired attribute DOMString ?;
reflectsAriaRoleDescription attribute DOMString ?;
reflectsAriaRowCount attribute DOMString ?;
reflectsAriaRowIndex attribute DOMString ?;
reflectsAriaRowIndexText attribute DOMString ?;
reflectsAriaRowSpan attribute DOMString ?;
reflectsAriaSelected attribute DOMString ?;
reflectsAriaSetSize attribute DOMString ?;
reflectsAriaSort attribute DOMString ?;
reflectsAriaValueMax attribute DOMString ?;
reflectsAriaValueMin attribute DOMString ?;
reflectsAriaValueNow attribute DOMString ?; };
reflectsAriaValueText
Interfaces that include `ShadowRootMixin` must provide the following algorithms:
-
`ShadowRootMixin` getter steps, which take the host interface instance, IDL attribute name, and content attribute name, and must return a string value; and
-
`ShadowRootMixin` setter steps, which take the host interface instance, IDL attribute name, content attribute name, and string value, and must return nothing.
For every IDL attribute idlAttribute defined in `ShadowRootMixin`, on getting, it must perform the following steps:
-
Let contentAttribute be the ReflectARIA content attribute determined by looking up idlAttribute in the ReflectARIA Attribute Correspondence table.
-
Return the result of running the `ShadowRootMixin` getter steps, given this, idlAttribute, and contentAttribute.
Similarly, on setting, it must perform the following steps:
-
Let contentAttribute be the ReflectARIA content attribute determined by looking up idlAttribute in the ReflectARIA Attribute Correspondence table.
-
Run the `ShadowRootMixin` setter steps, given this, idlAttribute, contentAttribute, and the given value.
2.5. ShadowRoot Attribute Correspondence
The following table provides a correspondence between IDL attribute names and content attribute names, for use by `ShadowRootMixin`.
2.6. `ShadowRootMixin` Mixed in to `ShadowRoot`
User agents MUST include `ShadowRootMixin` on `ShadowRoot`:
ShadowRoot includes ShadowRootMixin ;
For `ShadowRoot`:
-
The `ShadowRootMixin` getter steps given element, idlAttribute, and contentAttribute are to return the result of the getter algorithm for idlAttribute reflecting<contentAttribute on element.
-
The `ShadowRootMixin` setter steps given element, idlAttribute, contentAttribute, and value are to perform the setter algorithm for idlAttribute reflecting contentAttribute on element, given value.
Note: In practice, this means that, e.g., the `reflectsAriaAtomic` IDL on `ShadowRoot` reflects the `reflectsariaatomic` content attribute; etc
2.7. ShadowRootExtInit
[Exposed =Window ]dictionary :
ShadowRootExtInit ShadowRootInit {boolean =
reflectsAriaDescribedBy false ;boolean =
reflectsAriaAtomic false ;boolean =
reflectsAriaAutoComplete false ;boolean =
reflectsAriaBusy false ;boolean =
reflectsAriaChecked false ;boolean =
reflectsAriaColCount false ;boolean =
reflectsAriaColIndex false ;boolean =
reflectsAriaColIndexText false ;boolean =
reflectsAriaColSpan false ;boolean =
reflectsAriaCurrent false ;boolean =
reflectsAriaDescription false ;boolean =
reflectsAriaDisabled false ;boolean =
reflectsAriaExpanded false ;boolean =
reflectsAriaHasPopup false ;boolean =
reflectsAriaHidden false ;boolean =
reflectsAriaInvalid false ;boolean =
reflectsAriaKeyShortcuts false ;boolean =
reflectsAriaLabel false ;boolean =
reflectsAriaLevel false ;boolean =
reflectsAriaLive false ;boolean =
reflectsAriaModal false ;boolean =
reflectsAriaMultiLine false ;boolean =
reflectsAriaMultiSelectable false ;boolean =
reflectsAriaOrientation false ;boolean =
reflectsAriaPlaceholder false ;boolean =
reflectsAriaPosInSet false ;boolean =
reflectsAriaPressed false ;boolean =
reflectsAriaReadOnly false ;boolean =
reflectsAriaRequired false ;boolean =
reflectsAriaRoleDescription false ;boolean =
reflectsAriaRowCount false ;boolean =
reflectsAriaRowIndex false ;boolean =
reflectsAriaRowIndexText false ;boolean =
reflectsAriaRowSpan false ;boolean =
reflectsAriaSelected false ;boolean =
reflectsAriaSetSize false ;boolean =
reflectsAriaSort false ;boolean =
reflectsAriaValueMax false ;boolean =
reflectsAriaValueMin false ;boolean =
reflectsAriaValueNow false ;boolean =
reflectsAriaValueText false ; };
2.8. attachShadow Signature
User agents MUST update the attachShadow method signature in the Element
with the ShadowRootExtInit option, as the following:
ShadowRoot attachShadow(ShadowRootExtInit init);
2.9. attachShadow Extension
The `attachShadow` method steps have their last 2 steps with:
-
Set each attribute in the § 2.9.1 Reflects Aria Attribute Correspondence {#reflects-correspondence} table into shadow to the corresponding init[reflects attribute].
-
Set this’s shadow root to shadow.
-
Return shadow.
2.9.1. Reflects Aria Attribute Correspondence {#reflects-correspondence}
Attribute | reflects |
---|---|
reflects ariaDescribedBy | reflectsAriaDescribedBy |
reflects ariaAtomic | reflectsAriaAtomic |
reflects ariaAutoComplete | reflectsAriaAutoComplete |
reflects ariaBusy | reflectsAriaBusy |
reflects ariaChecked | reflectsAriaChecked |
reflects ariaColCount | reflectsAriaColCount |
reflects ariaColIndex | reflectsAriaColIndex |
reflects ariaColIndexText | reflectsAriaColIndexText |
reflects ariaColSpan | reflectsAriaColSpan |
reflects ariaCurrent | reflectsAriaCurrent |
reflects ariaDescription | reflectsAriaDescription |
reflects ariaDisabled | reflectsAriaDisabled |
reflects ariaExpanded | reflectsAriaExpanded |
reflects ariaHasPopup | reflectsAriaHasPopup |
reflects ariaHidden | reflectsAriaHidden |
reflects ariaInvalid | reflectsAriaInvalid |
reflects ariaKeyShortcuts | reflectsAriaKeyShortcuts |
reflects ariaLabel | reflectsAriaLabel |
reflects ariaLevel | reflectsAriaLevel |
reflects ariaLive | reflectsAriaLive |
reflects ariaModal | reflectsAriaModal |
reflects ariaMultiLine | reflectsAriaMultiLine |
reflects ariaMultiSelectable | reflectsAriaMultiSelectable |
reflects ariaOrientation | reflectsAriaOrientation |
reflects ariaPlaceholder | reflectsAriaPlaceholder |
reflects ariaPosInSet | reflectsAriaPosInSet |
reflects ariaPressed | reflectsAriaPressed |
reflects ariaReadOnly | reflectsAriaReadOnly |
reflects ariaRequired | reflectsAriaRequired |
reflects ariaRoleDescription | reflectsAriaRoleDescription |
reflects ariaRowCount | reflectsAriaRowCount |
reflects ariaRowIndex | reflectsAriaRowIndex |
reflects ariaRowIndexText | reflectsAriaRowIndexText |
reflects ariaRowSpan | reflectsAriaRowSpan |
reflects ariaSelected | reflectsAriaSelected |
reflects ariaSetSize | reflectsAriaSetSize |
reflects ariaSort | reflectsAriaSort |
reflects ariaValueMax | reflectsAriaValueMax |
reflects ariaValueMin | reflectsAriaValueMin |
reflects ariaValueNow | reflectsAriaValueNow |
reflects ariaValueText | reflectsAriaValueText |