Customizing Events

new CustomEvent(type, { detail }) carries any data in event.detail, and since 2020 all major browsers let your classes extend EventTarget, so plain objects can emit events without a library.

A cart that announces changesJavaScript
class Cart extends EventTarget {
  #items = [];
  add(item) {
    this.#items.push(item);
    this.dispatchEvent(new CustomEvent("cart:change", { detail: this.#items.length }));
  }
}
const cart = new Cart();
cart.addEventListener("cart:change", (e) => console.log(`${e.detail} item(s)`));
cart.add("pen");
cart.add("ink");
Output
1 item(s)
2 item(s)

Prefix custom names (cart:change) to avoid clashes with future built-in events. From inside a shadow root, add bubbles: true, composed: true.