Beyond built-in DOM events like click, JavaScript lets you define and dispatch your own custom events — a clean way to decouple different parts of an application without them directly calling each other.
// Dispatching a custom event with data
const event = new CustomEvent('cart:updated', {
detail: { itemCount: 3, total: 59.97 },
bubbles: true,
});
document.dispatchEvent(event);
// Listening for it anywhere else in the app - no direct coupling needed
document.addEventListener('cart:updated', (e) => {
console.log(<code>Cart now has ${e.detail.itemCount} items</code>);
updateCartBadge(e.detail.itemCount);
});
A Simple Pub/Sub System Built on This
class EventBus extends EventTarget {
emit(name, detail) {
this.dispatchEvent(new CustomEvent(name, { detail }));
}
on(name, handler) {
this.addEventListener(name, handler);
}
}
const bus = new EventBus();
bus.on('user:login', (e) => console.log('Logged in:', e.detail));
bus.emit('user:login', { userId: 42 });
This pattern lets a cart component, a notification badge, and an analytics tracker all react to the same “cart updated” moment without any of them needing a direct reference to each other — genuinely useful for decoupling unrelated parts of a larger application.