Testare Elementi Personalizzati che Utilizzano ElementInternals

This page is not available in the language you requested. You have been redirected to the English version of the page.
Link to this page copied to clipboard

Come Axe DevTools per Web legge le semantiche ARIA da ElementInternals, cosa devono fare i tuoi componenti per esporle e quali linguaggi lo supportano.

Not for use with personal data

I componenti web possono dichiarare le loro semantiche di accessibilità in JavaScript anziché nel markup, chiamando attachInternals() e impostando proprietà come role e ariaLabel sull'oggetto ElementInternals restituito. Un componente costruito in questo modo non ha attributi role o aria-* nel DOM, quindi uno strumento di test che legge solo gli attributi vede un elemento privo di qualsiasi semantica.

Axe DevTools per Web legge ora queste semantiche. Questa pagina spiega quali versioni lo supportano, cosa devono fare i tuoi componenti per rendere visibili i loro interni e come gli interni interagiscono con gli attributi già presenti sull'elemento. Per informazioni generali sulla selezione della tua versione di axe-core, vedi Personalizzazione delle regole.

Linguaggi e Versioni Supportate

Il supporto viene dal motore di test dell'accessibilità sottostante, quindi è disponibile ovunque la versione axe-core inclusa sia la 4.13.0 o superiore.

Linguaggio Versione che ha aggiunto il supporto axe-core incluso
C# 4.13.0 4.13.0
Python 4.13.0 4.13.0
Ruby 4.13.0 4.13.0 (attraverso axe-core-api 4.13.0)
Java 4.13.0 4.13.0 (attraverso com.deque.html.axe-core 4.13.0)
Node.js e il CLI 4.13.0 4.13.0
note

Non c'è nulla da attivare. In ogni linguaggio sopra, il motore di test dell'accessibilità viene eseguito direttamente nella pagina sottoposta a test, quindi legge ElementInternals a ogni scansione senza alcuna opzione, flag o modifica della configurazione. Se i tuoi componenti seguono già il protocollo descritto di seguito, è sufficiente un aggiornamento.

Esporre ElementInternals ad Axe DevTools

ElementInternals è privato per progettazione: JavaScript non fornisce alcuna API per leggere gli interni di un altro elemento. Uno strumento di test può vedere l'oggetto solo se il tuo componente lo pubblica deliberatamente. Gli autori dei componenti lo fanno tramite un protocollo della comunità, e Axe DevTools supporta ogni forma di quel protocollo.

La forma consigliata è un WeakMap globale, che tiene l'oggetto fuori dall'elemento stesso:

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);
    }
  }
);

Assegnare l'oggetto a una proprietà sull'elemento funziona anche:

customElements.define(
  'my-custom-button',
  class MyCustomButton extends HTMLElement {
    constructor() {
      super();

      this._internals = this.attachInternals();
      this._internals.role = 'button';
    }
  }
);

Oltre alla mappa globalThis._elementInternals, Axe DevTools cerca l'oggetto sotto uno di questi nomi sull'elemento:

  • _internals (consigliato)
  • internals
  • internals_
  • Symbol('internals')
  • Symbol('privateInternals')
important

Un componente che mantiene i suoi interni realmente privati è invisibile ad Axe DevTools, e questa è la ragione più comune per non vedere alcun cambiamento dopo l'aggiornamento. Due casi da controllare:

  • Campi di classe privati. this.#internals = this.attachInternals() non può essere letto all'esterno della classe, quindi nessuno strumento di test può vederlo. Molte librerie di componenti utilizzano questo modello.
  • Getter. Una proprietà che è definita come accessor piuttosto che un valore semplice viene ignorata, anche se è chiamata _internals. Assegna l'oggetto direttamente.

In entrambi i casi, la correzione appartiene al componente, non alla configurazione del tuo test. Pubblica l'oggetto tramite una delle forme sopra, o aspettati che l'elemento venga valutato come se non avesse semantiche ARIA.

Testare che i tuoi componenti siano visibili ad Axe DevTools non richiede una scansione. Nella console del browser su una pagina che utilizza il componente, globalThis._elementInternals?.get(document.querySelector('my-custom-button')) o document.querySelector('my-custom-button')._internals dovrebbe restituire un oggetto ElementInternals anziché undefined.

Cosa Legge Axe DevTools

Una volta che l'oggetto è visibile, Axe DevTools legge la proprietà role e le proprietà ARIA che corrispondono agli attributi aria-*, come ariaLabel per aria-label, ariaDescription per aria-description e ariaLabelledByElements per aria-labelledby. Questi valori alimentano le stesse regole che sarebbero state eseguite sugli attributi equivalenti, quindi un elemento personalizzato che imposta role e ariaLabel tramite gli interni è verificato per un nome accessibile nello stesso modo di uno che imposta role e aria-label nel markup.

Precedenza

I valori presenti nel DOM vincono sempre. Questo significa che aggiungere attributi al tuo markup è un modo affidabile per sovrascrivere ciò che un componente dichiara internamente, e che gli interni non mascherano mai un problema visibile nel DOM.

  • Ruolo. Il role da ElementInternals è trattato come il ruolo implicito dell'elemento, con lo stesso status del ruolo incorporato di un elemento nativo. Un attributo role esplicito sull'elemento lo sovrascrive.
  • Valori ARIA. Ogni valore è risolto prima dall'attributo, poi dalla proprietà corrispondente sull'elemento, e solo infine da ElementInternals.

Limitazioni

Il supporto è reale ma non ancora completo, ed è utile conoscere le lacune prima di interpretare una scansione.

Le regole che selezionano su attributi non corrispondono a elementi solo interni. Un certo numero di regole identifica gli elementi a cui si applicano con un selettore CSS contro il DOM. Poiché un elemento la cui semantica deriva solo da ElementInternals non ha un attributo role, tali regole non vengono mai applicate contro di esso. Ad esempio, aria-required-attr seleziona [role] e aria-command-name seleziona [role="link"], [role="button"], [role="menuitem"]. Un elemento personalizzato che dichiara role = 'button' tramite internals non viene valutato da nessuna delle due regole. Le regole che risolvono il ruolo anziché corrispondere a un selettore, come quelle che calcolano un nome accessibile, si applicano.

I valori dei ruoli non sono convalidati. Un role impostato tramite internals viene utilizzato come dato. Un valore non valido o scritto male non viene segnalato come farebbe un attributo role non valido.

Alcune regole vengono applicate solo parzialmente. Le regole che esaminano la relazione di un elemento con i suoi figli o antenati, come aria-required-children, potrebbero non valutare completamente un elemento solo interno.

A causa della prima limitazione in particolare, aspettarsi che un componente che dichiara la propria semantica solo tramite internals produca meno risultati rispetto al markup equivalente, piuttosto che di più. Una scansione pulita di un tale componente è una prova meno forte di una scansione pulita di uno che utilizza attributi.