Start · Sprachen · JavaScript · Referenz · CustomEvent

CustomEvent

Schnittstelle

Ein <code>Event</code>, das über die Eigenschaft <code>detail</code> beliebige anwendungsspezifische Daten an Listener weitergibt.

seit JavaScript DOM Level 3 / Konstruktor: Baseline in allen moder Kategorie: webapi

Signatur

interface CustomEvent&lt;T = any&gt; extends Event

Beschreibung

CustomEvent erweitert Event um die schreibgeschützte Eigenschaft detail. Darin lassen sich beliebige Daten ablegen, etwa Objekte, Arrays oder primitive Werte. Das Ereignis wird mit new CustomEvent(type, options) erzeugt und mit EventTarget.dispatchEvent() an einem Element, an window, document oder einem eigenen EventTarget ausgelöst.

Typische Einsatzfälle sind die lose gekoppelte Kommunikation zwischen Komponenten (z. B. Web Components, die "item-selected" nach außen melden), ein einfaches Publish/Subscribe-System auf Basis von EventTarget und das Signalisieren von Zustandsänderungen, ohne dass Aufrufer und Empfänger sich direkt kennen.

Das Ereignis durchläuft das DOM nach den üblichen Regeln. Ohne bubbles: true steigt es nicht im DOM auf, ohne cancelable: true hat preventDefault() keine Wirkung, und ohne composed: true bleibt es innerhalb eines Shadow-DOM. dispatchEvent() arbeitet synchron: Alle Listener laufen durch, bevor der Aufruf zurückkehrt.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Name des Ereignisses, z. B. "cart:updated". Groß- und Kleinschreibung wird unterschieden. Empfohlen sind Kleinbuchstaben mit Bindestrich oder Doppelpunkt.
$options CustomEventInit {} Optionales Objekt mit folgenden Feldern:
  • detail (any, Standard null): die mitgesendeten Daten.
  • bubbles (boolean, Standard false): Das Ereignis steigt im DOM auf.
  • cancelable (boolean, Standard false): Das Ereignis lässt sich mit preventDefault() abbrechen.
  • composed (boolean, Standard false): Das Ereignis überschreitet Shadow-DOM-Grenzen.

Rückgabewert

Typ
CustomEvent
Beschreibung
Eine neue CustomEvent-Instanz. Die mitgegebenen Daten liegen schreibgeschützt in event.detail.

Beispiele

Ereignis erzeugen, auslösen und detail auslesen

const button = document.createElement('button');

button.addEventListener('user:login', (event) => {
  console.log(`Willkommen, ${event.detail.name}!`);
  console.log(event instanceof CustomEvent, event.bubbles);
});

const loginEvent = new CustomEvent('user:login', {
  detail: { name: 'Anna', id: 42 }
});

button.dispatchEvent(loginEvent);
Willkommen, Anna! true false

Web Component meldet eine Auswahl nach außen (bubbles + composed)

class ColorPicker extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.innerHTML = '<button data-color="red">Rot</button><button data-color="blue">Blau</button>';
    shadow.addEventListener('click', (e) => {
      const color = e.target.dataset.color;
      if (!color) return;
      this.dispatchEvent(new CustomEvent('color-change', {
        detail: { color },
        bubbles: true,
        composed: true
      }));
    });
  }
}
customElements.define('color-picker', ColorPicker);

document.body.append(document.createElement('color-picker'));

// Listener weiter oben im DOM – funktioniert dank bubbles/composed
document.addEventListener('color-change', (e) => {
  document.body.style.background = e.detail.color;
  console.log('Neue Farbe:', e.detail.color);
});
Neue Farbe: red (nach Klick auf "Rot")

Abbrechbares Ereignis: Aktion per preventDefault() verhindern

const form = document.createElement('form');

form.addEventListener('before-save', (e) => {
  if (e.detail.title.trim() === '') {
    e.preventDefault(); // Speichern verhindern
  }
});

const save = (data) => {
  const event = new CustomEvent('before-save', { detail: data, cancelable: true });
  const allowed = form.dispatchEvent(event); // false, wenn abgebrochen
  console.log(allowed ? 'Gespeichert' : 'Speichern abgebrochen');
};

save({ title: '' });
save({ title: 'Bericht Q3' });
Speichern abgebrochen Gespeichert

Einfacher Event-Bus mit EventTarget

class EventBus extends EventTarget {
  emit(type, detail) {
    this.dispatchEvent(new CustomEvent(type, { detail }));
  }
  on(type, handler) {
    const listener = (e) => handler(e.detail);
    this.addEventListener(type, listener);
    return () => this.removeEventListener(type, listener); // Abmelden
  }
}

const bus = new EventBus();
const off = bus.on('cart:updated', ({ count }) => console.log(`Warenkorb: ${count} Artikel`));

bus.emit('cart:updated', { count: 3 });
off();
bus.emit('cart:updated', { count: 4 }); // keine Ausgabe mehr
Warenkorb: 3 Artikel

// Wichtig · Fallstricke

  • Standardmäßig kein Bubbling: Ohne bubbles: true erreicht das Ereignis nur Listener direkt am Ziel. Delegierte Listener an document bekommen es dann nicht mit. Das ist ein sehr häufiger Fehler.
  • Shadow DOM: Soll ein Ereignis eine Web Component verlassen, wenn es im Shadow-Root ausgelöst wurde, braucht es zusätzlich composed: true.
  • detail ist schreibgeschützt: Die Eigenschaft selbst kann nicht neu zugewiesen werden. Ein übergebenes Objekt bleibt aber veränderbar, und alle Listener teilen sich dieselbe Referenz. Wer Nebenwirkungen vermeiden will, übergibt eine Kopie oder friert das Objekt mit Object.freeze() ein.
  • Synchron: dispatchEvent() ruft alle Listener sofort nacheinander auf. Wirft ein Listener eine Ausnahme, wird sie gemeldet, die übrigen Listener laufen aber weiter.
  • Veraltete API: document.createEvent('CustomEvent') zusammen mit initCustomEvent() gilt als veraltet. Heute nutzt man immer den Konstruktor. Der Internet Explorer unterstützte den Konstruktor nicht und brauchte ein Polyfill.
  • isTrusted ist bei selbst ausgelösten Ereignissen immer false. Sicherheitsrelevante Entscheidungen, etwa ob eine echte Nutzeraktion vorliegt, dürfen sich nicht auf eigene Ereignisse stützen.
  • Node.js: CustomEvent ist seit Node.js 19 global verfügbar, in Node.js 18 nur mit dem Flag --experimental-global-customevent.
  • Eindeutige Ereignisnamen mit Präfix (z. B. "myapp:ready") verhindern Konflikte mit nativen oder fremden Ereignissen.