Start · Sprachen · JavaScript · Referenz · ElementInternals.ariaOwnsElements

ElementInternals.ariaOwnsElements

Eigenschaft

Legt als Standard-Semantik eines Custom Elements fest, welche Elemente es im Barrierefreiheitsbaum als Kinder „besitzt“ – das Gegenstück zu <code>aria-owns</code>, nur mit Elementreferenzen.

seit JavaScript Neu (ARIA-Elementreflexion): Safari 16.4+, Chromiu Kategorie: webapi

Signatur

ElementInternals.ariaOwnsElements

Beschreibung

Die Eigenschaft ariaOwnsElements von ElementInternals enthält ein Array von Elementen, die einem Custom Element im Barrierefreiheitsbaum als (zusätzliche) Kinder zugeordnet werden. Das ist nötig, wenn die DOM-Hierarchie nicht der logischen Beziehung zwischen Eltern- und Kindelement entspricht, etwa wenn die Popup-Liste einer Combobox aus technischen Gründen am Ende von document.body hängt.

Anders als das Attribut aria-owns, das eine durch Leerzeichen getrennte Liste von IDs erwartet, arbeitet die Eigenschaft direkt mit Elementobjekten. Man braucht also keine IDs zu vergeben. Weil sie über ElementInternals gesetzt wird, legt sie die Standard-Semantik des Custom Elements fest: Sie ist nicht als Attribut im DOM sichtbar, und Nutzer der Komponente können sie jederzeit mit einem eigenen aria-owns-Attribut am Host überschreiben.

Typischerweise setzt man den Wert im Konstruktor oder in connectedCallback(), nachdem man mit this.attachInternals() das ElementInternals-Objekt geholt hat. Wenn man null zuweist, wird die Beziehung wieder aufgehoben.

Parameter

Name Typ Default Beschreibung
$value Array<Element> | null null Wert, der beim Setzen zugewiesen wird: ein Array von Elementen, die das Custom Element besitzen soll. Mit null wird die Zuordnung entfernt.

Rückgabewert

Typ
ReadonlyArray<Element> | null
Beschreibung
Ein eingefrorenes Array der zugeordneten Elemente oder null, wenn nichts gesetzt ist. Ungültige Referenzen, etwa Elemente außerhalb des erlaubten Geltungsbereichs, werden beim Lesen herausgefiltert.

Beispiele

Custom Combobox besitzt ein ausgelagertes Listbox-Popup

class MyCombobox extends HTMLElement {
  #internals;
  #listbox;

  constructor() {
    super();
    this.#internals = this.attachInternals();
    this.#internals.role = 'combobox';
  }

  connectedCallback() {
    // Popup hängt aus Layout-Gründen direkt am body
    this.#listbox = document.createElement('ul');
    this.#listbox.setAttribute('role', 'listbox');
    ['Berlin', 'Hamburg', 'München'].forEach((stadt) => {
      const li = document.createElement('li');
      li.setAttribute('role', 'option');
      li.textContent = stadt;
      this.#listbox.append(li);
    });
    document.body.append(this.#listbox);

    // Logische Beziehung für Screenreader herstellen
    this.#internals.ariaOwnsElements = [this.#listbox];
  }

  disconnectedCallback() {
    this.#internals.ariaOwnsElements = null;
    this.#listbox?.remove();
  }
}

customElements.define('my-combobox', MyCombobox);

Wert lesen und korrekt ergänzen

class OwnerBox extends HTMLElement {
  internals = this.attachInternals();

  addOwned(el) {
    const aktuell = this.internals.ariaOwnsElements ?? [];
    // Das zurückgegebene Array ist eingefroren – neues Array zuweisen
    this.internals.ariaOwnsElements = [...aktuell, el];
  }
}
customElements.define('owner-box', OwnerBox);

const box = document.createElement('owner-box');
document.body.append(box);

const a = document.createElement('div');
const b = document.createElement('div');
document.body.append(a, b);

box.addOwned(a);
box.addOwned(b);
console.log(box.internals.ariaOwnsElements.length);
console.log(Object.isFrozen(box.internals.ariaOwnsElements));
2 true

Feature-Erkennung mit Fallback auf aria-owns

const setOwned = (host, internals, elements) => {
  if ('ariaOwnsElements' in ElementInternals.prototype) {
    internals.ariaOwnsElements = elements;
  } else {
    // Fallback: IDs vergeben und Attribut setzen
    const ids = elements.map((el) => {
      el.id ||= `owned-${crypto.randomUUID()}`;
      return el.id;
    });
    host.setAttribute('aria-owns', ids.join(' '));
  }
};

// Wichtig · Fallstricke

  • Geltungsbereich: Referenzierte Elemente müssen im selben DOM-Baum wie der Host liegen oder in einem Baum, der ihn über Shadow-Grenzen hinweg umschließt. Elemente im eigenen Shadow Root des Hosts oder in fremden Shadow Roots sind ungültig und werden beim Lesen herausgefiltert.
  • Eingefrorenes Array: Methoden wie push() auf dem gelesenen Wert schlagen fehl oder wirken nicht. Man muss immer ein neues Array zuweisen.
  • Vorrang: Ein am Host gesetztes aria-owns-Attribut oder element.ariaOwnsElements überschreibt die Standard-Semantik aus ElementInternals.
  • Sparsam einsetzen: aria-owns verändert den Barrierefreiheitsbaum. Wenn möglich, besser die DOM-Struktur passend aufbauen. Ein Element sollte nur einen einzigen Besitzer haben.
  • Kompatibilität: Die Unterstützung für ARIA-Elementreflexion ist noch jung und uneinheitlich. Vorher per Feature-Erkennung prüfen und gegebenenfalls auf das ID-basierte Attribut ausweichen.