Signatur
Beschreibung
Die Eigenschaft ariaExpanded des ElementInternals-Interfaces spiegelt die ARIA-Eigenschaft aria-expanded wider. Sie teilt Hilfstechnologien wie Screenreadern mit, ob ein Gruppierungselement, das dieses Element besitzt oder steuert, gerade aufgeklappt ("true") oder zugeklappt ("false") ist. Das ist zum Beispiel bei einem Akkordeon-Kopf, einem Menü-Button oder einer Combobox der Fall.
Den Unterschied zu Element.ariaExpanded macht der Ort, an dem der Wert steht: Über ElementInternals legt ein Custom Element seine Standard-Semantik intern fest. Im Light DOM erscheint dabei kein aria-expanded-Attribut. Das Markup bleibt also sauber, und Nutzer der Komponente können den Wert trotzdem mit einem eigenen Attribut am Host-Element überschreiben.
Das ElementInternals-Objekt bekommt man im Konstruktor oder im Lebenszyklus der Komponente über this.attachInternals(). Diese Methode lässt sich pro Element nur einmal aufrufen. Den Rückgabewert speichert man deshalb am besten in einem privaten Feld.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $wert | string | null | null | Beim Setzen: "true" (aufgeklappt), "false" (zugeklappt), "undefined" (das Element steuert nichts, was sich ein- oder ausklappen lässt) oder null (entfernt den Standardwert). |
Rückgabewert
"true", "false", "undefined") oder null, wenn nichts gesetzt ist.Beispiele
Aufklappbarer Bereich als Custom Element
class DisclosureToggle extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
this.#internals.role = 'button';
this.#internals.ariaExpanded = 'false';
this.tabIndex = 0;
this.addEventListener('click', () => this.toggle());
}
toggle() {
const offen = this.#internals.ariaExpanded === 'true';
this.#internals.ariaExpanded = String(!offen);
console.log('ariaExpanded:', this.#internals.ariaExpanded);
}
}
customElements.define('disclosure-toggle', DisclosureToggle);
const el = document.createElement('disclosure-toggle');
document.body.append(el);
el.click();
Kein Attribut im DOM sichtbar
class MenuButton extends HTMLElement {
constructor() {
super();
const internals = this.attachInternals();
internals.role = 'button';
internals.ariaExpanded = 'false';
console.log(this.hasAttribute('aria-expanded'), internals.ariaExpanded);
}
}
customElements.define('menu-button', MenuButton);
document.body.append(document.createElement('menu-button'));
Zustand mit einem Popup synchronisieren
class AccordionHeader extends HTMLElement {
#internals = this.attachInternals();
connectedCallback() {
this.#internals.role = 'button';
const panel = document.getElementById(this.getAttribute('for'));
const sync = () => {
this.#internals.ariaExpanded = panel.hidden ? 'false' : 'true';
};
sync();
this.addEventListener('click', () => {
panel.hidden = !panel.hidden;
sync();
});
}
}
customElements.define('accordion-header', AccordionHeader);
// Wichtig · Fallstricke
- Nur Zeichenketten: Der Wert wird als String gespeichert. Ein Vergleich wie
internals.ariaExpanded === trueist deshalb immerfalse. Vergleiche besser mit=== 'true'. - Autoren-Attribute haben Vorrang: Setzt jemand
aria-expandeddirekt am Host-Element, gilt dieser Wert und nicht der ausElementInternals. - Nur für autonome Custom Elements:
attachInternals()löst bei eingebauten Elementen und bei angepassten eingebauten Elementen (is="…") eineNotSupportedErroraus. - Passende Rolle nötig:
aria-expandedist nur für bestimmte Rollen erlaubt, etwabutton,combobox,treeitemoderrow. Setze deshalb auchinternals.role. - Browser-Unterstützung: Die ARIA-Reflexion über
ElementInternalsgibt es erst seit Firefox 119 und Safari 16.4. Für ältere Browser prüfst du am besten mit'ariaExpanded' in ElementInternals.prototypeund setzt als Ausweichlösung das Attribut.