Tester les Éléments Personnalisés Utilisant ElementInternals
Comment Axe DevTools pour le Web lit les sémantiques ARIA à partir d'ElementInternals, ce que vos composants doivent faire pour les exposer, et quelles langues le supportent.
Les composants web peuvent déclarer leurs sémantiques d'accessibilité en JavaScript au lieu de le faire dans le balisage, en appelant attachInternals() et en définissant des propriétés telles que role et ariaLabel sur l'objet ElementInternals retourné. Un composant construit de cette manière n'a pas d'attributs role ou aria-* dans le DOM, de sorte qu'un outil de test qui lit uniquement les attributs voit un élément sans sémantique du tout.
Axe DevTools pour le Web lit maintenant ces sémantiques. Cette page explique quelles versions le supportent, ce que vos composants doivent faire pour rendre leurs internals visibles, et comment les internals interagissent avec les attributs déjà présents sur l'élément. Pour des informations générales sur le choix de votre version axe-core, voir Personnalisation des Règles.
Langues et Versions Supportées
Le support provient du moteur de test d'accessibilité sous-jacent, donc il est disponible partout où la version axe-core intégrée est 4.13.0 ou supérieure.
| Langue | Version qui a ajouté le support | Axe-core intégré |
|---|---|---|
| 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 et le CLI | 4.13.0 | 4.13.0 |
Il n'y a rien à activer. Dans chaque langue ci-dessus, le moteur de test d'accessibilité fonctionne directement sur la page à tester, donc il lit ElementInternals à chaque analyse sans option, drapeau ou changement de configuration. Si vos composants suivent déjà le protocole décrit ci-dessous, il n'y a qu'à mettre à jour.
Exposer ElementInternals à Axe DevTools
ElementInternals est privé par conception : JavaScript ne fournit aucune API pour lire les internals d'un autre élément. Un outil de test ne peut voir l'objet que si votre composant le publie délibérément. Les auteurs de composants le font par le biais d'un protocole communautaire, et Axe DevTools supporte toutes les formes de ce protocole.
La forme recommandée est un WeakMap global, qui garde l'objet en dehors de l'élément lui-même :
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);
}
}
);Attribuer l'objet à une propriété sur l'élément fonctionne aussi :
customElements.define(
'my-custom-button',
class MyCustomButton extends HTMLElement {
constructor() {
super();
this._internals = this.attachInternals();
this._internals.role = 'button';
}
}
);En plus de la carte globalThis._elementInternals, Axe DevTools recherche l'objet sous n'importe lequel de ces noms sur l'élément :
_internals(recommandé)internalsinternals_Symbol('internals')Symbol('privateInternals')
Un composant qui garde ses internals réellement privés est invisible pour Axe DevTools, et c'est la raison la plus courante de ne voir aucun changement après la mise à jour. Deux cas à vérifier :
- Champs de classe privés.
this.#internals = this.attachInternals()ne peuvent pas être lus de l'extérieur de la classe, donc aucun outil de test ne peut le voir. Plusieurs bibliothèques de composants utilisent ce modèle. - Accesseurs. Une propriété définie comme un accessoire plutôt qu'une valeur simple est ignorée, même si elle est nommée
_internals. Attribuez l'objet directement.
Dans les deux cas, la correction appartient au composant, non à votre configuration de test. Publiez l'objet par l'une des formes ci-dessus, ou attendez-vous à ce que l'élément soit évalué comme s'il n'avait pas de sémantiques ARIA.
Tester que vos composants sont visibles pour Axe DevTools n'a pas besoin d'un scan. Dans la console du navigateur sur une page qui utilise le composant, globalThis._elementInternals?.get(document.querySelector('my-custom-button')) ou document.querySelector('my-custom-button')._internals devrait renvoyer un objet ElementInternals plutôt que undefined.
Ce que lit Axe DevTools
Une fois que l'objet est visible, Axe DevTools lit la propriété role et les propriétés ARIA qui correspondent aux attributs aria-*, tels que ariaLabel pour aria-label, ariaDescription pour aria-description, et ariaLabelledByElements pour aria-labelledby. Ces valeurs alimentent les mêmes règles qui auraient été appliquées aux attributs équivalents, de sorte qu'un élément personnalisé qui fixe role et ariaLabel via les internals est vérifié pour un nom accessible de la même manière qu'un élément qui fixe role et aria-label dans le balisage.
Prépondérance
Les valeurs présentes dans le DOM l'emportent toujours. Cela signifie que l'ajout d'attributs à votre balisage est un moyen fiable de remplacer ce qu'un composant déclare en interne, et que les internals ne masquent jamais un problème visible dans le DOM.
- Rôle. Le
roledeElementInternalsest considéré comme le rôle implicite de l'élément, ayant le même statut que le rôle intégré d'un élément natif. Un attributroleexplicite sur l'élément le remplace. - Valeurs ARIA. Chaque valeur est d'abord résolue à partir de l'attribut, puis de la propriété correspondante sur l'élément, et seulement ensuite à partir de
ElementInternals.
Limitations
Le support est réel mais pas encore complet, et il est utile de connaître les lacunes avant d'interpréter une analyse.
Les règles qui se basent sur les attributs ne correspondent pas aux éléments internes uniquement. Certaines règles identifient les éléments auxquels elles s'appliquent avec un sélecteur CSS sur le DOM. Comme un élément dont la sémantique provient uniquement de ElementInternals n'a pas d'attribut role, ces règles ne sont jamais appliquées à cet élément. Par exemple, aria-required-attr sélectionne [role], et aria-command-name sélectionne [role="link"], [role="button"], [role="menuitem"]. Un élément personnalisé déclarant role = 'button' via des internes n'est évalué par aucune des deux règles. Les règles qui résolvent le rôle plutôt que de correspondre à un sélecteur, telles que celles calculant un nom accessible, s'appliquent.
Les valeurs de rôle ne sont pas validées. Un role défini via des internes est utilisé tel quel. Une valeur invalide ou mal orthographiée n'est pas signalée de la même manière qu'un attribut role invalide le serait.
Certaines règles ne sont appliquées que partiellement. Les règles qui examinent la relation d'un élément avec ses enfants ou ancêtres, telles que aria-required-children, peuvent ne pas évaluer complètement un élément uniquement interne.
En raison de la première limitation en particulier, attendez-vous à ce qu'un composant qui déclare sa sémantique uniquement par des internes produise moins de résultats que le balisage équivalent ne le ferait, plutôt que plus. Une analyse propre d'un tel composant constitue une preuve moins solide qu'une analyse propre d'un composant utilisant des attributs.
Pages connexes
- Personnalisation des règles pour sélectionner la version axe-core que vos analyses utilisent.
- À propos d'Axe DevTools pour les API Web pour la liste complète des langues et frameworks pris en charge.
- Documentation de l'API C#, Aperçu de Python, Utilisation avancée de l'API avec Ruby, Aperçu de l'API Java, et Tests basés sur Node.js et le navigateur pour les liaisons linguistiques qui prennent cela en charge.
