Start · Sprachen · JavaScript · Referenz · HTMLSlotElement: slotchange

HTMLSlotElement: slotchange

Ereignis

Wird auf einem <code>&lt;slot&gt;</code>-Element ausgelöst, wenn sich die ihm zugewiesenen Knoten ändern, also wenn Light-DOM-Inhalte hinzukommen, entfernt oder neu zugeordnet werden.

seit JavaScript Baseline: alle modernen Browser (seit 2020) Kategorie: webapi

Signatur

slot.addEventListener("slotchange", handler)

Beschreibung

Das Ereignis slotchange gehört zu HTMLSlotElement. Es wird ausgelöst, wenn sich die Menge der zugewiesenen Knoten eines Slots ändert. Das passiert etwa, wenn ein Kind-Element mit passendem slot-Attribut in den Host eingefügt oder entfernt wird, wenn sich das slot-Attribut eines Kindes ändert oder wenn bei manueller Slot-Zuweisung slot.assign() aufgerufen wird.

Web Components nutzen das Ereignis, um auf Inhalte zu reagieren, die ein Nutzer der Komponente hineinreicht. Typische Fälle sind Tab-Leisten, die ihre Tabs aus den übergebenen Kindern erzeugen, Listen, die Einträge zählen, oder Komponenten, die geslottete Elemente mit ARIA-Attributen versehen. Die aktuellen Knoten liest man im Handler mit slot.assignedNodes() oder slot.assignedElements() aus.

Das Ereignis bubbelt (bubbles: true), ist aber nicht composed. Es verlässt also den Shadow-Tree nicht. Deshalb kann man es auch zentral am shadowRoot abfangen und über event.target herausfinden, welcher Slot betroffen ist. Es ist nicht abbrechbar und hat den Typ Event. Statt addEventListener kann man auch die Eigenschaft slot.onslotchange setzen.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "slotchange".
$handler Pflicht (event: Event) => void Callback, der ein normales Event erhält. event.target ist der betroffene HTMLSlotElement.
$options boolean | AddEventListenerOptions false Optionen wie once, signal oder capture.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück.

Beispiele

Geslottete Elemente zählen

class ItemList extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({ mode: 'open' });
    root.innerHTML = `<p>Einträge: <span id="count">0</span></p><slot></slot>`;
    const slot = root.querySelector('slot');
    const count = root.getElementById('count');

    slot.addEventListener('slotchange', () => {
      const items = slot.assignedElements();
      count.textContent = items.length;
      console.log('Einträge:', items.length);
    });
  }
}
customElements.define('item-list', ItemList);

const list = document.createElement('item-list');
list.innerHTML = '<li>A</li><li>B</li>';
document.body.append(list);

// Später einen Eintrag ergänzen
setTimeout(() => list.append(Object.assign(document.createElement('li'), { textContent: 'C' })), 500);
Einträge: 2 Einträge: 3

Zentral am shadowRoot abfangen (benannte Slots)

class CardBox extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({ mode: 'open' });
    root.innerHTML = `
      <header><slot name="title"></slot></header>
      <main><slot></slot></main>`;

    // slotchange bubbelt innerhalb des Shadow-Trees
    root.addEventListener('slotchange', (event) => {
      const slot = event.target;
      console.log(`Slot "${slot.name || 'default'}" hat jetzt ${slot.assignedNodes().length} Knoten`);
    });
  }
}
customElements.define('card-box', CardBox);

const card = document.createElement('card-box');
card.innerHTML = '<h2 slot="title">Hallo</h2><p>Inhalt</p>';
document.body.append(card);
Slot "title" hat jetzt 1 Knoten Slot "default" hat jetzt 1 Knoten

on-Property verwenden und Listener wieder entfernen

const host = document.createElement('div');
const root = host.attachShadow({ mode: 'open' });
const slot = document.createElement('slot');
root.append(slot);
document.body.append(host);

// Variante 1: on-Property
slot.onslotchange = () => console.log('onslotchange:', slot.assignedNodes().length);

// Variante 2: addEventListener mit anschließendem Entfernen
const handler = () => console.log('Listener aktiv');
slot.addEventListener('slotchange', handler);

host.append(document.createElement('span'));

setTimeout(() => {
  slot.removeEventListener('slotchange', handler);
  slot.onslotchange = null;
  host.append(document.createElement('span')); // keine Ausgabe mehr
}, 100);
onslotchange: 1 Listener aktiv

// Wichtig · Fallstricke

  • Nur direkte Kinder zählen: Ändert sich etwas innerhalb eines geslotteten Elements (z. B. Text oder Enkel-Elemente), wird kein slotchange ausgelöst. Für solche Änderungen braucht man einen MutationObserver.
  • Asynchron und gebündelt: Das Ereignis wird als Microtask ausgelöst, so ähnlich wie bei Mutation Observern. Mehrere Änderungen direkt hintereinander ergeben meist nur ein Ereignis.
  • Erste Zuweisung: Ob der Slot beim Upgrade schon vorhandener Light-DOM-Kinder ein Ereignis bekommt, hängt davon ab, ob der Listener vor der Zuweisung registriert war. Man sollte daher zusätzlich einmal direkt assignedElements() auslesen, zum Beispiel in connectedCallback.
  • Nicht composed: Außerhalb des Shadow-Roots, etwa am Host oder an document, kommt das Ereignis nicht an.
  • Verschachtelte Slots: Mit assignedNodes({ flatten: true }) werden auch weitergereichte Slot-Inhalte aufgelöst.
  • Kompatibilität: Chrome 53+, Firefox 63+, Safari 10.1+, Edge 79+. Die IDL-Eigenschaft onslotchange gibt es in älteren Versionen teilweise erst später, deshalb ist addEventListener die sicherere Wahl.