How does addEventListener work?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
addEventListener registers a function to run when a given event fires on an element.
button.addEventListener("click", (event) => {
console.log(event.target);
});
Why not onclick
el.onclick = fn allows only one handler — assigning a second silently replaces the first. addEventListener allows many, and gives you options the property form cannot express.
The options object
el.addEventListener("click", fn, {
once: true, // remove automatically after the first call
capture: true, // run during the capture phase instead of bubble
passive: true, // promise not to call preventDefault
signal: ctrl.signal, // remove when the controller aborts
});
passive: true on wheel and touchstart lets the browser scroll without waiting to see whether you cancel — a real scrolling-performance win. It is the default for those events, so you must pass passive: false if you do need preventDefault().
Removing listeners
removeEventListener needs the same function reference and matching capture value:
el.addEventListener("click", () => {});
el.removeEventListener("click", () => {}); // does nothing — different function
The signal option avoids this bookkeeping entirely and removes many listeners at once:
const ctrl = new AbortController();
el.addEventListener("click", onClick, { signal: ctrl.signal });
window.addEventListener("resize", onResize, { signal: ctrl.signal });
ctrl.abort(); // both gone
Two practical points
Inside a regular function, this is the element; inside an arrow function it is not — use event.currentTarget, which works either way.
And for many similar children, attach one listener to the container and use event.target.closest() instead of one listener per child. Fewer listeners, and it keeps working for elements added later.
