Custom Events & EventTarget API
debt(d7/e3/b3/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated=no and that ESLint is the only listed tool, but the code_pattern describes indirect symptoms (global variables, tight coupling, direct function calls) rather than detectable API misuse. Missing bubbles:true, leaked listeners, or premature dispatch are not caught by standard ESLint rules and typically only surface during integration testing or runtime debugging.
Closest to 'simple parameterised fix' (e3). The quick_fix suggests replacing direct component coupling with CustomEvent dispatch/listen — a small, localised refactor within the communication path between two components. Adding bubbles:true or wiring up removeEventListener are one-to-few line changes, though adopting a naming convention may touch several files within one component cluster.
Closest to 'localised tax' (b3). The applies_to scope is web contexts only (frontend), and the tags confirm a frontend pattern. Misuse (leaked listeners, missing bubbles, no naming convention) imposes a tax on the components involved but doesn't structurally shape the whole codebase. The pattern is opt-in and contained to the communication layer between specific components.
Closest to 'notable trap' (t5). The misconception field identifies that devs undervalue custom events (thinking they're framework-only), and common_mistakes highlight concrete gotchas: forgetting bubbles:true silently breaks cross-component communication, and listener leaks cause memory issues that aren't obvious. These are documented gotchas most developers eventually discover, matching the t5 anchor.
Also Known As
TL;DR
Explanation
CustomEvent allows any DOM element to dispatch events with arbitrary data in the detail property. EventTarget can be subclassed to create a non-DOM event emitter. Patterns: component A dispatches 'cart:updated' on document, component B listens without knowing about A. This decouples components without shared state or direct references. The EventTarget mixin also enables event-driven communication in Web Workers and custom objects. Bubbling and capture phases allow event delegation.
Common Misconception
Why It Matters
Common Mistakes
- Not setting bubbles: true when cross-component communication is needed — non-bubbling events don't propagate.
- Not removing event listeners — addEventListener without removeEventListener causes memory leaks.
- Dispatching events before the target element exists in the DOM.
- Using string event names without a naming convention — namespace with colon: 'cart:updated', 'user:login'.
Code Examples
// Tight coupling — direct function calls:
class Cart {
update(items) {
this.items = items;
checkout.refresh(); // Direct reference — Cart knows about Checkout
analytics.track(); // Cart knows about Analytics
header.updateBadge(); // Cart knows about Header
}
}
// Decoupled via custom events:
class Cart {
update(items) {
this.items = items;
document.dispatchEvent(new CustomEvent('cart:updated', {
bubbles: true,
detail: { items, count: items.length }
}));
// Cart knows nothing about who listens
}
}
// Independent listeners:
document.addEventListener('cart:updated', e => checkout.refresh(e.detail));
document.addEventListener('cart:updated', e => analytics.track(e.detail));
document.addEventListener('cart:updated', e => header.updateBadge(e.detail.count));