Make a Button Do Something With addEventListener
Find the button, attach a listener, change something on the page when it's clicked. Three steps, and two mistakes that make it silently do nothing.
You want a button that does something when it's clicked. It takes three steps: find the button, attach a listener, change something in the listener. Then there are two mistakes that make it silently do nothing, and you'll probably make one of them at least once. Let's do it properly.
Skip ahead: If your button already works and you're here because it doesn't, jump to "It does nothing: check these first".
The page
Save this as index.html, with a script.js next to it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Counter</title>
</head>
<body>
<p>Cups of coffee today: <span id="count">0</span></p>
<button id="add" type="button">Add a cup</button>
<button id="reset" type="button">Reset</button>
<script src="script.js"></script>
</body>
</html>
The script tag is at the end of <body>, so the buttons exist when the script runs. That one detail prevents the most common problem.
Step 1: Find the button
const addButton = document.querySelector("#add");
const resetButton = document.querySelector("#reset");
const countEl = document.querySelector("#count");
#add means "the element with id add". If you used a class, it would be .add.
Step 2: Attach a listener
let count = 0;
addButton.addEventListener("click", () => {
count++;
countEl.textContent = count;
});
addEventListener takes the event name and a function. The browser calls the function every time the button is clicked. Nothing inside runs until then.
Step 3: Change something on the page
That's the countEl.textContent = count; line. The page shows the new number. Add the reset button the same way:
resetButton.addEventListener("click", () => {
count = 0;
countEl.textContent = count;
});
Here's the whole script.js:
const addButton = document.querySelector("#add");
const resetButton = document.querySelector("#reset");
const countEl = document.querySelector("#count");
let count = 0;
function render() {
countEl.textContent = count;
resetButton.disabled = count === 0;
}
addButton.addEventListener("click", () => {
count++;
render();
});
resetButton.addEventListener("click", () => {
count = 0;
render();
});
render();
The render function keeps "what the page shows" in one place. Both buttons change count, then call it. As the page grows, that saves you from updating the same element from five places and forgetting one.
It does nothing: check these first
Open the console (F12) before anything else. Then go down this list.
1. Red error "Cannot read properties of null (reading 'addEventListener')". querySelector found nothing. The id is misspelled, you used . for an id or # for a class, or the script runs in the <head> before the button exists. Fix the selector, or move the script to the end of <body>, or add defer: <script src="script.js" defer></script>.
2. No error, and nothing happens. You probably called the function instead of passing it:
addButton.addEventListener("click", addCup()); // wrong: calls it now
addButton.addEventListener("click", addCup); // right: passes it
The first line runs addCup once, immediately, while the page loads, and attaches whatever it returns (usually undefined). The second line is right: pass the function, don't call it.
⚠ Warning: A button inside a <form> is a submit button by default. Clicking it submits the form and reloads the page, so your change flashes and disappears. Add type="button" to buttons that aren't meant to submit, like in the HTML above. If it is a form, listen for submit on the form and call event.preventDefault().
3. It works, but runs twice (or more). You attached the listener more than once, often by putting addEventListener inside another listener or inside a function that runs repeatedly. Attach listeners once, when the page loads.
4. Wrong file. The console shows 404 for script.js, or your changes aren't showing. Check the file name and folder, save, and reload.
Using the event object
The function gets an event with details. event.target is the element that was clicked. That lets one listener handle many buttons:
<div id="sizes">
<button type="button" data-size="S">Small</button>
<button type="button" data-size="M">Medium</button>
<button type="button" data-size="L">Large</button>
</div>
<p id="picked">No size picked</p>
document.querySelector("#sizes").addEventListener("click", (event) => {
const size = event.target.dataset.size;
if (!size) return;
document.querySelector("#picked").textContent = `Size: ${size}`;
});
dataset.size reads the data-size attribute. The if (!size) return; ignores clicks on the gaps between buttons.
💡 Tip: Use a real <button> for things that do something, not a <div> with a click listener. A button can be reached with the Tab key, works with Enter and Space, and screen readers announce it. A clickable div does none of that unless you add it all yourself.
Common mistakes
addEventListener("click", fn())instead offn.- Script in the
<head>withoutdefer. - Forgetting
type="button"inside forms. "onclick"as the event name. The event is"click".onclickis the old attribute.
Now try it: add a "Remove a cup" button that never lets the count go below zero. Where does the check go?
About
Wire up a button with querySelector and addEventListener, update the page on click, and fix the usual reasons nothing happens. After this, your button actually does something.
- Responsible
- Mary Q
- Last Update
- 08/28/2026
- Reading Time
- 5 min
Reviews
Sign in to write a reviewComments (0)
Sign in to commentNo comments yet.