Signatur
Beschreibung
Die Eigenschaft ariaDetailsElements des ElementInternals-Interfaces legt fest, welche Elemente ausführliche, zugängliche Details zu einem autonomen Custom Element liefern. Sie entspricht semantisch dem ARIA-Attribut aria-details, arbeitet aber mit direkten Elementreferenzen statt mit ID-Listen.
Der entscheidende Unterschied zum gleichnamigen Attribut: Über ElementInternals gesetzte Werte sind Standard-Semantik des Elements. Sie erscheinen nicht als sichtbares Attribut im DOM und werden überschrieben, sobald der Autor des Elements selbst aria-details bzw. element.ariaDetailsElements setzt. So kann eine Komponente sinnvolle Vorgaben machen, ohne das Markup der Nutzer zu verschmutzen.
Typische Anwendungsfälle sind Komponenten mit umfangreichen Zusatzinformationen: Diagramme mit Datentabelle, Formularfelder mit ausführlicher Hilfe oder Bilder mit Langbeschreibung. Anders als ariaDescribedByElements (kurze, vorgelesene Beschreibung) verweist ariaDetailsElements auf strukturierte Inhalte, zu denen Screenreader-Nutzer gezielt navigieren können.
Beim Lesen wird ein neues, eingefrorenes Array zurückgegeben; Änderungen erfolgen deshalb immer durch Zuweisung eines neuen Arrays. Referenzierte Elemente müssen im selben Dokument liegen und – je nach Scope-Regeln – aus Sicht des Hosts erreichbar sein (z. B. im eigenen Shadow Root oder im Light DOM bzw. einem übergeordneten Scope).
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value | Array<Element> | null | null | Beim Setzen: Array von Elementen, die Details bereitstellen. null entfernt die Standard-Semantik wieder. |
Rückgabewert
null, wenn keine gesetzt sind. Nicht mehr verbundene oder nicht erreichbare Elemente werden beim Lesen herausgefiltert.Beispiele
Diagramm-Komponente verweist auf Datentabelle im Shadow DOM
class DataChart extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = `
<canvas width="300" height="150"></canvas>
<details>
<summary>Daten als Tabelle</summary>
<table id="daten"><tr><th>Monat</th><th>Umsatz</th></tr>
<tr><td>Jan</td><td>1200</td></tr></table>
</details>`;
this.#internals.role = 'img';
this.#internals.ariaLabel = 'Umsatzdiagramm';
// Standard-Semantik: Tabelle liefert die Details
this.#internals.ariaDetailsElements = [root.querySelector('#daten')];
}
get detailElements() {
return this.#internals.ariaDetailsElements;
}
}
customElements.define('data-chart', DataChart);
const chart = document.createElement('data-chart');
document.body.append(chart);
console.log(chart.detailElements.map((el) => el.id));
Details dynamisch austauschen und entfernen
class HelpField extends HTMLElement {
static observedAttributes = ['help-for'];
#internals = this.attachInternals();
attributeChangedCallback(name, oldValue, newValue) {
const help = newValue ? document.getElementById(newValue) : null;
// Neues Array zuweisen – das gelesene Array ist eingefroren
this.#internals.ariaDetailsElements = help ? [help] : null;
}
}
customElements.define('help-field', HelpField);
document.body.insertAdjacentHTML('beforeend', `
<section id="hilfe-passwort">Mindestens 12 Zeichen, eine Ziffer …</section>
<help-field help-for="hilfe-passwort"></help-field>`);
const field = document.querySelector('help-field');
field.removeAttribute('help-for'); // setzt wieder auf null
Feature-Erkennung mit Fallback
class InfoBox extends HTMLElement {
connectedCallback() {
const internals = this.attachInternals();
const details = document.querySelector('#info-details');
if (!details) return;
if ('ariaDetailsElements' in ElementInternals.prototype) {
internals.ariaDetailsElements = [details];
} else if (!this.hasAttribute('aria-details')) {
// Fallback: ID-basiertes Attribut (funktioniert nicht über Shadow-Grenzen)
this.setAttribute('aria-details', details.id);
}
}
}
customElements.define('info-box', InfoBox);
// Wichtig · Fallstricke
- Browser-Unterstützung: Die Element-Reflection-Eigenschaften (
ariaDetailsElementsu. a.) sind noch nicht in allen Browsern verfügbar. Immer per'ariaDetailsElements' in ElementInternals.prototypeprüfen. - Kein Direkt-Mutieren: Das zurückgegebene Array ist eingefroren;
push()wirft im Strict Mode einenTypeError. Stattdessen ein neues Array zuweisen. - Vorrang: Setzt der Nutzer der Komponente
aria-detailsoderelement.ariaDetailsElements, überschreibt das den Wert ausElementInternals. - Scope-Regeln: Elemente in einem tieferen Shadow Root (z. B. im Shadow DOM eines anderen Elements) sind nicht gültig und werden beim Lesen ignoriert.
attachInternals()darf pro Element nur einmal aufgerufen werden und funktioniert nur bei autonomen Custom Elements.- Die Screenreader-Unterstützung für
aria-detailsist uneinheitlich – wichtige Informationen zusätzlich sichtbar bzw. überariaDescribedByElementszugänglich machen.