Het testen van Custom Elements die ElementInternals gebruiken
Hoe Axe DevTools voor Web ARIA-semanticagegevens leest van ElementInternals, wat jouw componenten moeten doen om ze bloot te leggen en welke talen dit ondersteunen.
Webcomponenten kunnen hun toegankelijkheidssemantiek in JavaScript declareren in plaats van in markup, door attachInternals() aan te roepen en eigenschappen zoals role en ariaLabel in te stellen op het geretourneerde ElementInternals-object. Een op deze manier gebouwde component heeft geen role- of aria-*-attributen in de DOM, dus een testtool die alleen attributen leest, ziet een element zonder enige semantiek.
Axe DevTools voor Web leest nu deze semantiek. Deze pagina legt uit welke versies dit ondersteunen, wat je componenten moeten doen om hun internals zichtbaar te maken en hoe internals interageren met de attributen die al op het element staan. Voor algemene informatie over het selecteren van je axe-core versie, zie Regels aanpassen.
Ondersteunde Talen en Versies
Ondersteuning komt van de onderliggende toegankelijkheidstestengine, dus het is beschikbaar overal waar de gebundelde axe-core versie 4.13.0 of hoger is.
| Taal | Versie die ondersteuning toevoegde | Gebundelde axe-core |
|---|---|---|
| C# | 4.13.0 | 4.13.0 |
| Python | 4.13.0 | 4.13.0 |
| Ruby | 4.13.0 | 4.13.0 (via axe-core-api 4.13.0) |
| Java | 4.13.0 | 4.13.0 (via com.deque.html.axe-core 4.13.0) |
| Node.js en de CLI | 4.13.0 | 4.13.0 |
Er hoeft niets te worden ingeschakeld. In elke bovenstaande taal draait de toegankelijkheidstestengine rechtstreeks op de te testen pagina, dus het leest ElementInternals bij elke scan zonder optie, vlag of configuratieverandering. Als je componenten al het hieronder beschreven protocol volgen, is upgraden alles wat nodig is.
ElementInternals blootleggen aan Axe DevTools
ElementInternals is van nature privé: JavaScript biedt geen API voor het lezen van de internals van een ander element. Een testtool kan het object alleen zien als je component het doelbewust publiceert. Componenteigenaars doen dit via een communityprotocol, en Axe DevTools ondersteunt elke vorm van dat protocol.
De aanbevolen vorm is een globale WeakMap, die het object van het element zelf weghoudt:
customElements.define(
'my-custom-button',
class MyCustomButton extends HTMLElement {
constructor() {
super();
const internals = this.attachInternals();
internals.role = 'button';
globalThis._elementInternals ??= new WeakMap();
globalThis._elementInternals.set(this, internals);
}
}
);Het object toewijzen aan een eigenschap op het element werkt ook:
customElements.define(
'my-custom-button',
class MyCustomButton extends HTMLElement {
constructor() {
super();
this._internals = this.attachInternals();
this._internals.role = 'button';
}
}
);Naast de globalThis._elementInternals-map zoekt Axe DevTools naar het object onder een van deze namen op het element:
_internals(aanbevolen)internalsinternals_Symbol('internals')Symbol('privateInternals')
Een component die zijn internals echt privé houdt, is onzichtbaar voor Axe DevTools, en dit is de meest voorkomende reden om geen veranderingen te zien na een upgrade. Twee situaties om te controleren:
- Privé klassevelden.
this.#internals = this.attachInternals()kan niet van buiten de klasse worden gelezen, dus geen enkele testtool kan het zien. Verschillende componentbibliotheken gebruiken dit patroon. - Getters. Een eigenschap die is gedefinieerd als een toegangsmethode in plaats van een gewone waarde wordt overgeslagen, zelfs als het is genoemd
_internals. Wijs het object direct toe.
In beide gevallen hoort de oplossing in de component en niet in je testconfiguratie. Publiceer het object via een van de bovenstaande vormen, of verwacht dat het element wordt geëvalueerd alsof het geen ARIA-semanticagegevens heeft.
Het testen of je componenten zichtbaar zijn voor Axe DevTools heeft geen scan nodig. In de browserconsole op een pagina die de component gebruikt, moeten globalThis._elementInternals?.get(document.querySelector('my-custom-button')) of document.querySelector('my-custom-button')._internals een ElementInternals-object retourneren in plaats van undefined.
Wat Axe DevTools leest
Zodra het object zichtbaar is, leest Axe DevTools de role-eigenschap en de ARIA-eigenschappen die overeenkomen met aria-*-attributen, zoals ariaLabel voor aria-label, ariaDescription voor aria-description en ariaLabelledByElements voor aria-labelledby. Deze waarden voeden dezelfde regels die zouden zijn toegepast op de equivalente attributen, dus een custom element dat role en ariaLabel instelt via internals wordt gecontroleerd op een toegankelijke naam op dezelfde manier als een dat role en aria-label instelt in markup.
Voorrang
Waarden die in de DOM aanwezig zijn, winnen altijd. Dit betekent dat het toevoegen van attributen aan je markup een betrouwbare manier is om te overschrijven wat een component intern verklaart, en dat internals nooit een probleem maskeren dat zichtbaar is in de DOM.
- Rol. De
rolevanElementInternalswordt behandeld als de impliciet-rol van het element, met dezelfde status als de ingebouwde rol van een native element. Een explicietrole-attribuut op het element overschrijft het. - ARIA-waarden. Elke waarde wordt eerst opgelost uit het attribuut, dan de overeenkomstige eigenschap op het element en pas daarna uit
ElementInternals.
Beperkingen
Ondersteuning is weliswaar reëel maar nog niet volledig, en de tekortkomingen zijn het waard om te weten voordat je een scan interpreteert.
Regels die op attributen selecteren komen niet overeen met alleen-internal-elementen. Een aantal regels identificeert de elementen waarop ze van toepassing zijn met een CSS-selector tegen de DOM. Omdat een element waarvan de semantiek alleen uit ElementInternals komt geen role-attribuut heeft, worden die regels er nooit op toegepast. Bijvoorbeeld, aria-required-attr selecteert [role], en aria-command-name selecteert [role="link"], [role="button"], [role="menuitem"]. Een aangepast element dat role = 'button' via internals verklaart, wordt door geen van beide regels geëvalueerd. Regels die de rol oplossen in plaats van een selector te matchen, zoals diegenen die een toegankelijke naam berekenen, zijn wel van toepassing.
Rolwaarden worden niet gevalideerd. Een role die via internals is ingesteld, wordt gebruikt zoals gegeven. Een ongeldige of verkeerd gespelde waarde wordt niet gerapporteerd zoals een ongeldig role-attribuut dat zou zijn.
Sommige regels worden slechts gedeeltelijk toegepast. Regels die de relatie van een element tot zijn kinderen of voorouders onderzoeken, zoals aria-required-children, kunnen een alleen-internal-element mogelijk niet volledig evalueren.
Vanwege de eerste beperking in het bijzonder, verwacht je dat een component dat zijn semantiek alleen via internals verklaart, minder bevindingen oplevert dan het equivalente markup zou doen, in plaats van meer. Een schone scan van zo'n component is zwakker bewijs dan een schone scan van een die attributen gebruikt.
Verwante Pagina's
- Aanpassen van Regels voor het selecteren van de axe-core-versie die je scans gebruiken.
- Over Axe DevTools voor Web-API's voor de volledige lijst van ondersteunde talen en frameworks.
- C# API Documentatie, Python overzicht, Geavanceerd API-gebruik met Ruby, Java API Overzicht en Node.js en Browsergebaseerd Testen voor de taalbindings die dit ondersteunen.
