Een schaduwgrens verandert de werking van semantiek en ARIA. Er zijn 2 veelvoorkomende fouten: ontbrekende semantiek in de schaduwstructuur en ARIA-verwijzingen die ongemerkt worden verbroken omdat ze geen schaduwroots kunnen overschrijden.
Begin met semantische opmaak: gebruik echte <button>, <nav>, <ul> in de template zodat de meeste semantiek kosteloos is en reserveer ElementInternals/ARIA voor de gaten.
Standaard semantiek via de ElementInternals ARIA-mixin
Stel de rol en ARIA-status van een aangepast element in JS in via ElementInternals in plaats van ARIA-kenmerken naar de host te schrijven. Zo blijven de semantische elementen de standaardwaarden die de component bezit, terwijl een consument ze nog steeds kan overschrijven met kenmerken in de Light DOM.
class ToggleSwitch extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
this.#internals.role = 'switch'; // default role, no host attribute needed
this.#internals.ariaChecked = 'false'; // exposed to the accessibility tree
this.addEventListener('click', () => this.toggle());
this.addEventListener('keydown', (e) => {
if (e.key === ' ') { e.preventDefault(); this.toggle(); }
});
}
connectedCallback() {
// Put the host in the tab order on connect (setting tabIndex in the constructor throws on createElement).
if (!this.hasAttribute('tabindex')) this.tabIndex = 0;
}
toggle() {
const on = this.#internals.ariaChecked !== 'true';
this.#internals.ariaChecked = String(on);
}
}
customElements.define('toggle-switch', ToggleSwitch);
Zo wordt de DOM niet vervuild met ARIA-kenmerken en kunnen consumenten ze niet per ongeluk overschrijven, terwijl de toegankelijkheidsstructuur nog steeds de juiste rol en status ziet.
Focusbeheer en delegatesFocus
- Als het hostelement zelf het interactieve bedieningselement is en de rol en status via
ElementInternals(zoalsToggleSwitchhierboven) draagt, plaats je de host in de tabvolgorde inconnectedCallback(if (!this.hasAttribute('tabindex')) this.tabIndex = 0, nooit in de constructor, die wordt geactiveerd opdocument.createElement) zodat de focus op de host komt te liggen en ondersteunende technologie de rol en status aankondigt. Steltabindexniet in op de host voor statische, niet-interactieve componenten (zoals een highlight of kaart). - Koppel de shadow root met
delegatesFocus: trueals de component een intern focusbaar bedieningselement omhult dat de semantiek bezit (of op een aan een formulier gekoppeld aangepast element metstatic formAssociated = true). Als je de host focust (en op een gekoppeld<label>voor aan een formulier gekoppelde elementen klikt), wordt de focus doorgestuurd naar het eerste focusbare onderliggende element en komt:focusovereen met de host. CombineerdelegatesFocus: trueniet met een rol/status op de host, anders komt de focus op het binnenste element te liggen en wordt de status van de host overgeslagen. - Voor een bewegende focus of een focus die naar een nieuw onthuld gebied wordt verplaatst, geef je het doel
tabindex="-1"en roep je.focus()aan. Maak programmatic focusbare doelen expliciet in plaats van te vertrouwen op de tabvolgorde.
ARIA-relaties tussen shadow roots
- VERPLICHT: Een
idwaarnaar wordt verwezen dooraria-labelledby,aria-describedby,aria-controls, enzovoort, wordt alleen omgezet binnen de eigen boom van het verwijzende element. Een opidgebaseerd kenmerk in de Light DOM kan niet verwijzen naar eenidin een schaduwstructuur en omgekeerd. De verwijzing wordt zonder melding genegeerd. - Als je de grens wilt overschrijden, gebruik je de gereflecteerde ARIA-element-property's (bijvoorbeeld
ariaLabelledByElements,ariaDescribedByElements, enzovoort), die directe JS-elementreferenties gebruiken in plaats van ID's. Ze worden naar buiten opgelost: een element in een schaduwstructuur kan verwijzen naar een doel in de Light DOM of een bovenliggende structuur (waaronder content in een slot). Je kunt dus een schaduwinterne bediening labelen vanuit Light DOM-content, iets watid-verwijzingen niet kunnen uitdrukken. - Ze worden niet naar binnen opgelost: een element kan niet verwijzen naar een onderliggende schaduwstructuur (een host kan bijvoorbeeld niet worden gelabeld door de eigen schaduwcontent). Voor die richting is het opkomende mechanisme Referentiedoel de standaardrichting, maar dit is nog niet breed beschikbaar.
- Als een relatie niet op een van beide manieren kan worden uitgedrukt, houd je deze binnen één boom (geef het label weer in dezelfde boom) of gebruik je
aria-label-tekst in plaats van eenid-verwijzing.
Reservestrategieën
Als de ElementInternals ARIA-mixin niet beschikbaar is, stel je de rol en ARIA-status in als kenmerken op de host (this.setAttribute('role', 'switch')). Dit werkt overal, maar gaat ten koste van het plaatsen van kenmerken in de DOM die een consument kan overschrijven.
Als de weerspiegelde ARIA-element-eigenschappen niet beschikbaar zijn, gebruik je een op id gebaseerd aria-*-kenmerk voor relaties in dezelfde boomstructuur. Een label dat de grens overschrijdt, heeft geen op id gebaseerd equivalent, dus val terug op aria-label-tekst.