Eine Shadow-Grenze ändert die Funktionsweise von Semantik und ARIA. Zwei Fehler dominieren: fehlende Semantik im Shadow Tree und ARIA-Referenzen, die unbemerkt fehlschlagen, weil sie nicht über Shadow Roots hinweg funktionieren.
Beginnen Sie mit semantischem Markup: Verwenden Sie echte <button>-, <nav>- und <ul>-Elemente in der Vorlage, damit die meisten semantischen Informationen automatisch vorhanden sind, und verwenden Sie ElementInternals/ARIA nur für die Lücken.
Standardsemantik über das ElementInternals-ARIA-Mixin
Legen Sie die Rolle und den ARIA-Status eines benutzerdefinierten Elements in JS über ElementInternals fest, anstatt ARIA-Attribute in den Host zu schreiben. So bleiben die Semantiken als Standardwerte erhalten, die die Komponente besitzt, während ein Nutzer sie weiterhin mit Attributen im Light DOM überschreiben kann.
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);
So wird verhindert, dass das DOM mit ARIA-Attributen überladen wird und Nutzer sie versehentlich überschreiben, während die Barrierefreiheitsstruktur weiterhin die richtige Rolle und den richtigen Status sieht.
Fokusverwaltung und delegatesFocus
- Wenn das Hostelement selbst das interaktive Steuerelement ist und die Rolle und den Status über
ElementInternals(wieToggleSwitchoben) trägt, fügen Sie den Host in die Tabulatorreihenfolge innerhalb vonconnectedCallbackein (if (!this.hasAttribute('tabindex')) this.tabIndex = 0– nie im Konstruktor, der beidocument.createElementeinen Fehler ausgibt), damit der Fokus auf dem Host liegt und die Hilfstechnologie seine Rolle und seinen Status ansagt. Legen Sietabindexauf dem Host nicht für statische, nicht interaktive Komponenten (z. B. ein Callout oder eine Karte) fest. - Hängen Sie den Shadow-Root mit
delegatesFocus: truean, wenn die Komponente ein internes fokussierbares Steuerelement umschließt, das die Semantik besitzt (oder bei einem formularbezogenen benutzerdefinierten Element mitstatic formAssociated = true). Wenn Sie den Host fokussieren (und bei formularbezogenen Elementen auf ein zugehöriges<label>klicken), wird der Fokus an das erste fokussierbare untergeordnete Element weitergeleitet und:focusstimmt mit dem Host überein. Kombinieren SiedelegatesFocus: truenicht mit einer Rolle/einem Status auf dem Host, da der Fokus sonst auf dem inneren Element liegt und der Status des Hosts übersprungen wird. - Wenn Sie den Fokus verschieben oder in einen neu angezeigten Bereich verschieben möchten, geben Sie dem Ziel
tabindex="-1"und rufen Sie.focus()auf. Machen Sie programmatisch fokussierbare Ziele explizit, anstatt sich auf die Tab-Reihenfolge zu verlassen.
ARIA-Beziehungen über Shadow-Roots hinweg
- OBLIGATORISCH: Ein
id, auf das vonaria-labelledby,aria-describedby,aria-controlsusw. verwiesen wird, wird nur innerhalb des eigenen Baums des verweisenden Elements aufgelöst. Einid-basiertes Attribut im Light DOM kann nicht auf eineidin einem Shadow Tree verweisen und umgekehrt. Die Referenz wird stillschweigend ignoriert. - Verwenden Sie zum Überschreiten der Grenze die reflektierten ARIA-Elementattribute (z. B.
ariaLabelledByElements,ariaDescribedByElementsusw.), die direkte JS-Elementreferenzen anstelle von IDs verwenden. Sie werden nach außen aufgelöst: Ein Element in einem Shadow Tree kann auf ein Ziel im Light DOM oder in einem beliebigen übergeordneten Baum (einschließlich Slotted Content) verweisen. So können Sie ein Shadow-internes Steuerelement aus Light DOM-Inhalten kennzeichnen – etwas, dasid-Referenzen nicht ausdrücken können. - Sie werden nicht nach innen aufgelöst: Ein Element kann nicht auf einen untergeordneten Shadow-Baum verweisen (z.B. kann ein Host nicht durch seinen eigenen Shadow-Inhalt gekennzeichnet werden). Für diese Richtung ist der neue Reference Target-Mechanismus der Standard, aber er ist noch nicht allgemein verfügbar.
- Wenn eine Beziehung auf keine der beiden Arten ausgedrückt werden kann, belassen Sie sie in einem Baum (rendern Sie das Label im selben Baum) oder verwenden Sie
aria-label-Text anstelle einerid-Referenz.
Fallback-Strategien
Wenn das ARIA-Mixin ElementInternals nicht verfügbar ist, legen Sie stattdessen die Rolle und den ARIA-Status als Attribute auf dem Host fest (this.setAttribute('role', 'switch')). Das funktioniert überall, allerdings werden dadurch Attribute im DOM platziert, die ein Nutzer überschreiben könnte.
Wenn die reflektierten ARIA-Elementeigenschaften nicht verfügbar sind, verwenden Sie ein id-basiertes aria-*-Attribut für Beziehungen im selben Baum. Ein grenzüberschreitendes Label hat kein id-basiertes Äquivalent. Verwenden Sie daher aria-label-Text.