addEventListener and removeEventListener
addEventListener() registers a handler function that the browser calls when a given event happens on an element, and removeEventListener() unregisters a handler that was added earlier. Both methods are available on any DOM node, as well as on window and document.
Theory
TL;DR
addEventListener(type, listener, options)subscribes a function to an event.- Any number of listeners can be attached to the same event.
- The handler receives an
eventobject with data about the event:type,targetand more. removeEventListener(type, listener, options)cancels the subscription.- Only the exact function that was added can be removed: a fresh anonymous arrow will not match.
- The
{ once, capture, passive }options control how the listener behaves.
Quick example
<button id="btn">Click me</button>const btn = document.querySelector('#btn');
function handleClick() {
alert('Button clicked!');
}
btn.addEventListener('click', handleClick);
// later, when the reaction is no longer needed
btn.removeEventListener('click', handleClick);The addEventListener signature
element.addEventListener(type, listener, options);| Argument | What it means |
|---|---|
type | a string, the event name ('click', 'input', 'keydown' and so on) |
listener | the function that runs when the event fires |
options (optional) | an object with extra settings, for example { once: true } |
Once subscribed, the handler is called every time the event reaches that element. The main advantage over the old onclick property is that there can be many listeners and they do not overwrite each other.
The event object
The browser passes the handler an event object carrying all the information about what happened:
btn.addEventListener('click', (event) => {
console.log(event.type); // "click"
console.log(event.target); // the element that was clicked
});Listener options
btn.addEventListener('click', handler, {
once: true, // the handler runs only once
capture: false, // listen on the bubbling phase, this is the default
passive: true, // tells the browser that preventDefault will not be called
});once: true detaches the listener automatically after the first run, so a separate removeEventListener call is no longer needed. passive: true lets the browser scroll without waiting for the handler, which noticeably improves smoothness on touch screens.
Removing a handler: the same function
element.removeEventListener(type, listener, options);Important: to remove a handler you have to pass the very same function you passed to
addEventListener.
Wrong:
btn.addEventListener('click', () => console.log('hi'));
btn.removeEventListener('click', () => console.log('hi')); // will not workHere two different anonymous functions are created, and the browser has no idea which one to drop.
Right:
function handleClick() {
console.log('hi');
}
btn.addEventListener('click', handleClick);
btn.removeEventListener('click', handleClick);Now the removal works.
A practical example and summary
function handleScroll() {
console.log('Scrolling!');
}
// start listening
window.addEventListener('scroll', handleScroll);
// stop listening after 3 seconds
setTimeout(() => {
window.removeEventListener('scroll', handleScroll);
console.log('Listener removed!');
}, 3000);| Method | What it does | Notes |
|---|---|---|
addEventListener() | adds an event handler | several listeners can be attached to one event |
removeEventListener() | removes a handler | works only with the same function object |
options | settings | { once, capture, passive } control the listener's behaviour |
Common mistakes
- Passing a new anonymous function, or a new
.bind(this)result, toremoveEventListener: the reference differs, so the listener stays attached. - Forgetting that
capturemust match: a listener added with{ capture: true }is only removed with the samecapturevalue. - Not detaching listeners from
windowordocumentwhen a component is destroyed, which causes memory leaks. - Calling
preventDefault()inside apassive: truelistener: the browser ignores it and logs a warning. - Attaching
addEventListeneron every re-render and piling up duplicate handlers.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.