addEventListener() is the standard way to react to events.
element.addEventListener(eventName, handlerFunction);
<button id="btn">Count</button>
<span id="count">0</span>
<script>
let count = 0;
const btn = document.querySelector("#btn");
function handleClick() {
count++;
document.querySelector("#count").textContent = count;
}
btn.addEventListener("click", handleClick);
</script>
Pass the function itself, not a call: handleClick, not handleClick(). With the parentheses the function would run immediately and its result would be passed along.
Arrow functions work too
btn.addEventListener("click", () => {
console.log("Clicked!");
});
Several listeners on one element
You can add as many as you like. They run in the order they were added.
btn.addEventListener("click", () => console.log("first"));
btn.addEventListener("click", () => console.log("second"));
Removing a listener
removeEventListener needs the same function reference. That is why anonymous arrow functions cannot be removed, and named functions can.
<button id="once">Click (works twice)</button>
<p id="out"></p>
<script>
let clicks = 0;
const button = document.querySelector("#once");
function handle() {
clicks++;
document.querySelector("#out").textContent = "Click " + clicks;
if (clicks === 2) {
button.removeEventListener("click", handle);
}
}
button.addEventListener("click", handle);
</script>
Options: once, passive, capture
A third argument can be an options object.
button.addEventListener("click", handler, { once: true }); // runs one time, then removes itself
window.addEventListener("scroll", handler, { passive: true }); // promises not to call preventDefault (smoother scrolling)
Why not onclick?
You may see onclick in HTML or as a property:
<button onclick="doSomething()">Old way</button>
button.onclick = function () { ... };
The property version holds one handler: assigning a second replaces the first. Inline attributes mix JavaScript into HTML and are harder to secure. addEventListener allows many handlers, offers options and works for every kind of event, so use it.
Listening for non-DOM events
addEventListener works on window, document, and many other objects, such as XMLHttpRequest or WebSocket.
window.addEventListener("resize", () => console.log(window.innerWidth));
Where does the code go?
Run it after the element exists: put the script at the end of the body, use defer, or wait for DOMContentLoaded. See Page Load Events.