Signatur
Beschreibung
Die Eigenschaft ariaControlsElements gehört zu ARIA Element Reflection. Sie bildet das Attribut aria-controls ab, arbeitet aber nicht mit ID-Zeichenketten, sondern direkt mit Element-Referenzen. So teilt man assistiven Technologien (etwa Screenreadern) mit, welche Elemente von einem Bedienelement gesteuert werden. Typische Fälle sind ein Button, der ein Akkordeon-Panel auf- und zuklappt, ein Tab, der sein Tabpanel steuert, oder eine Combobox mit ihrer Listbox.
Der große Vorteil gegenüber setAttribute("aria-controls", "id1 id2"): Die Zielelemente brauchen keine ID. Außerdem lassen sich Referenzen in bestimmten Fällen auch über Shadow-DOM-Grenzen hinweg setzen, nämlich wenn das Ziel in einem übergeordneten Scope liegt. Beim Lesen bekommt man ein eingefrorenes Array von Element-Objekten oder null, falls keine Zuordnung besteht.
Beim Setzen weist man ein Array von Elementen zu oder null, um die Zuordnung zu entfernen. Das Attribut aria-controls wird dabei auf einen leeren String gesetzt und nicht mit IDs gefüllt. Umgekehrt wertet der Getter ein gesetztes aria-controls-Attribut aus und liefert die passenden Elemente mit diesen IDs, solange keine explizite Zuweisung per Eigenschaft besteht.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value | Array<Element> | null | null | Nur beim Setzen: ein Array der gesteuerten Elemente oder null, um die Zuordnung zu entfernen. |
Rückgabewert
null, wenn keine Zuordnung besteht. Elemente, die nicht mehr im gültigen Scope liegen (z. B. aus dem DOM entfernt wurden), fehlen im Ergebnis.Beispiele
Akkordeon-Button ohne IDs mit seinem Panel verknüpfen
const button = document.createElement('button');
button.textContent = 'Details anzeigen';
button.ariaExpanded = 'false';
const panel = document.createElement('div');
panel.textContent = 'Versteckter Inhalt';
panel.hidden = true;
document.body.append(button, panel);
// Direkte Element-Referenz statt ID
button.ariaControlsElements = [panel];
button.addEventListener('click', () => {
const open = button.ariaExpanded === 'true';
button.ariaExpanded = String(!open);
for (const el of button.ariaControlsElements ?? []) {
el.hidden = open;
}
});
console.log(button.ariaControlsElements.length);
Aus vorhandenem aria-controls-Attribut lesen
// HTML: <button id="toggle" aria-controls="menu1 menu2">Menüs</button>
// <ul id="menu1"></ul><ul id="menu2"></ul>
const toggle = document.getElementById('toggle');
if ('ariaControlsElements' in Element.prototype) {
const ids = toggle.ariaControlsElements?.map((el) => el.id);
console.log(ids);
} else {
console.log('Nicht unterstützt – Attribut auswerten');
}
Zuordnung entfernen und Fallback
const tab = document.querySelector('[role="tab"]');
const tabpanel = document.querySelector('[role="tabpanel"]');
const setControls = (el, targets) => {
if ('ariaControlsElements' in Element.prototype) {
el.ariaControlsElements = targets;
} else if (targets) {
// Fallback: IDs sind hier nötig
el.setAttribute('aria-controls', targets.map((t) => t.id).join(' '));
} else {
el.removeAttribute('aria-controls');
}
};
setControls(tab, [tabpanel]);
setControls(tab, null);
console.log(tab.ariaControlsElements ?? null);
// Wichtig · Fallstricke
- Kompatibilität: ARIA Element Reflection ist relativ neu (Safari 16.4, Chromium 135, Firefox 136). Unterstützung per
'ariaControlsElements' in Element.prototypeprüfen und bei Bedarf auf das Attributaria-controlsmit IDs ausweichen. - Das zurückgegebene Array ist eingefroren.
el.ariaControlsElements.push(x)wirft deshalb einen Fehler. Man weist stattdessen ein neues Array zu:el.ariaControlsElements = [...(el.ariaControlsElements ?? []), x]. - Wird die Eigenschaft gesetzt, steht im Attribut
aria-controlsnur ein leerer String und keine IDs. Code oder CSS-Selektoren, die IDs im Attribut erwarten, funktionieren dann nicht mehr. - Shadow DOM: Aus einem Shadow Root heraus darf man auf Elemente in übergeordneten Scopes verweisen, aber nicht in fremde oder tieferliegende Shadow Roots. Solche Referenzen fehlen beim Lesen.
- Die Unterstützung für
aria-controlsist bei Screenreadern uneinheitlich (JAWS unterstützt es, NVDA und VoiceOver kaum). Man sollte sich deshalb nicht allein darauf verlassen und zusätzlicharia-expandedund eine logische DOM-Reihenfolge verwenden.