DOM Event Listener
addEventListener is the modern way to attach handlers. It supports options that solve real problems: passive scrolling, once-only fires, abortable signals.
The full signature
JS
el.addEventListener(type, handler, options);
// options can be a boolean (capture) or an object:
{
capture: false, // listen during capture phase
once: true, // remove after first fire
passive: true, // promise NOT to call preventDefault (faster scroll)
signal: ctrl.signal, // unhook via AbortController
}
Removing listeners
JS
// 1. Same function reference
function onClick() { /* … */ }
el.addEventListener("click", onClick);
el.removeEventListener("click", onClick);
// 2. AbortController — removes one or many at once
const ctrl = new AbortController();
el.addEventListener("click", fn1, { signal: ctrl.signal });
window.addEventListener("scroll", fn2, { signal: ctrl.signal });
ctrl.abort(); // unhooks both
Once and passive in practice
JS
// Run an init only the first time the user interacts
document.addEventListener("click", initAudio, { once: true });
// Passive listeners let the browser scroll smoothly — common for touchmove/wheel
window.addEventListener("scroll", onScroll, { passive: true });
Delegation
JS
document.querySelector("#todo-list").addEventListener("click", (e) => {
const item = e.target.closest("[data-id]");
if (!item) return;
if (e.target.matches("[data-delete]")) {
item.remove();
}
});
Tip: Anonymous arrows can't be removed by reference. If you'll ever want to detach, store the handler in a variable or use an
AbortController.Example
Example
<!DOCTYPE html>
<html>
<body>
<p id="out"></p>
<script>
document.getElementById("out").textContent = "Hello from DOM Event Listener!";
</script>
</body>
</html>
Try it Yourself »
Exercise
Run a listener only the first time, then auto-detach.
el.addEventListener('click', init, {
: true });
Four letters.
Discussion
Loading…