The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Event bubbling lets an event that starts on a nested element travel up through its ancestors. Event delegation uses that behavior: instead of attaching a separate click listener to every button, attach one listener to their shared parent and identify which button was clicked.
What event bubbling means
Browser events are provided by the Web Platform, rather than being a special feature of the JavaScript language. For an event that propagates through the DOM, dispatch has three phases: capture travels down from ancestors toward the target, the target phase runs listeners on the target, and bubbling travels back up through ancestors. MDN’s event bubbling guide illustrates how an ancestor can respond to an event that began on a descendant.
As an Amazon Associate I earn from qualifying purchases.
By default, addEventListener() registers a non-capturing listener. For an event that bubbles, a click on a button inside a list can therefore reach a listener attached to the list. The capture option changes when a listener runs; see MDN’s addEventListener() reference.
How event delegation works
Delegation is a way to handle interactions from multiple descendants with a listener on their shared ancestor. The handler checks the event’s origin, finds the relevant control, and responds only when that control belongs to the delegated region. It is especially useful for repeated controls and for descendants added after the parent listener is installed, provided the event bubbles to that parent.
#1 Best Overall
const list = document.querySelector(".todo-list");
list.addEventListener("click", (event) => {
const button = event.target.closest("button[data-action]");
if (!button || !list.contains(button)) return;
if (button.dataset.action === "remove") {
button.closest("li")?.remove();
}
});
Here, closest() means a click on an icon or span inside the button can still resolve to the button. The containment check keeps the match within this list. The selector and removal behavior should match your own markup and application.
Choose the right event target
event.target is the object where the event originated; it may be a nested icon rather than the button you intend to handle. event.currentTarget is the object whose listener is currently running—in this example, the list. Use the target to locate the intended descendant, and the current target when you need to refer to the delegation root. MDN documents these distinctions in its Event reference.
Rank #2
Delegation or a listener on each element?
| Approach | Useful when | Trade-off |
|---|---|---|
| One delegated listener on a shared ancestor | Many similar descendants share behavior, or relevant descendants may be added later. | The handler must identify the intended descendant correctly, and the event must reach the ancestor. |
| A listener on each element | A control is isolated, or keeping its behavior beside that element makes the code clearer. | Each relevant element needs its own listener and lifecycle handling. |
Delegation is a code-organization choice, not a guaranteed performance improvement. The cited documentation describes the pattern but does not establish a comparative performance benchmark. Consider the number and lifecycle of the elements, the clarity of the handler, and whether dynamic descendants need to be covered.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallPropagation is not the same as a browser default action
stopPropagation() stops an event from continuing to propagate; it does not cancel a default action such as following a link. If the event is cancelable and you need to prevent its default action, call preventDefault(). stopImmediatePropagation() also prevents other listeners on the same element from running. These methods solve different problems, so avoid stopping propagation as a routine way to silence an unwanted handler: doing so may keep unrelated ancestor listeners from seeing the event. See MDN’s stopPropagation() reference and Event reference.
Capture, non-bubbling events, and Shadow DOM
Use capture when timing matters
A capturing listener runs on the path toward the target, before the target phase. For ordinary delegated interactions, the default non-capturing listener is usually the relevant choice; use capture when an ancestor needs to run before the event reaches descendants. The option is documented in MDN’s addEventListener() reference.
Check whether the event bubbles
Delegation depends on the event reaching the ancestor listener. Not every event bubbles, so do not assume a parent listener will see every event from a child. For a custom event, inspect its bubbles setting as well as its other propagation options.
Rank #4
Account for Shadow DOM boundaries
An event crosses a Shadow DOM boundary only if it is composed; ordinary propagation through that boundary also requires bubbles to be true. composedPath() can help inspect the route, but a closed shadow root does not expose its internal nodes in that path. Consult MDN’s documentation for Event.composed and the Event interface when working across component boundaries.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




