JavaScript addEventListener: clicks, inputs and events
Learn addEventListener step by step: handle clicks, typing and form submits, use the event object, and avoid the mistakes that break listeners.

How do you make a web page react when someone clicks a button or types in a box?
Short answer: find the element, then call addEventListener with the name of the event and a function to run. The browser calls your function every time that event happens.
const button = document.querySelector("#save")
button.addEventListener("click", () => {
console.log("Saved!")
})By the end of this post you will be able to handle clicks, typing and form submits, read the event object, and spot the mistakes that make a listener silently do nothing. If finding elements with querySelector is new, read What the DOM is first.
How addEventListener works
Every call has the same shape:
element.addEventListener(type, listener)elementis the thing you are listening to, like a button, an input, a form, or the wholedocument.typeis the event name as a string:"click","input","submit","keydown".listeneris the function to run. You pass the function itself. The browser calls it later, when the event happens.
That last point is the whole idea. You aren't running the code now. You are handing the browser a function and saying "run this when it happens". Reacting To Events (opens in a new tab) explains the model in the course.
Handling a click
Here is a counter. The HTML has a button and a span:
<button id="like">Like</button>
<span id="count">0</span>The JavaScript finds both, keeps a number, and updates the page on every click:
const likeButton = document.querySelector("#like")
const countEl = document.querySelector("#count")
let likes = 0
likeButton.addEventListener("click", () => {
likes = likes + 1
countEl.textContent = likes
})The arrow function runs once per click. likes lives outside it, so the number survives between clicks. That works because of closures, which JavaScript closures explained covers in more depth. Try it in Your First Click Handler (opens in a new tab).
The event object
The browser passes your function one argument: an object describing what just happened. It is usually called event or e.
likeButton.addEventListener("click", (event) => {
console.log(event.type) // "click"
console.log(event.target) // the element that was clicked
})The properties you will use most:
| Property | What it tells you | Typical use |
|---|---|---|
event.target | The element the event started on | Which button in a list was clicked |
event.target.value | The current text of an input | Reading what the user typed |
event.key | The key that was pressed, like "Enter" | Keyboard shortcuts |
event.preventDefault() | Stops the browser's default action | Keeping a form from reloading the page |
The Event Object (opens in a new tab) goes through each of these.
Reacting to typing: input vs change
Inputs have two events that sound alike but fire at different times.
inputfires on every keystroke, paste or delete. Use it for live feedback.changefires when the value is committed. For a text box, that is when it loses focus after being edited. For a checkbox or a dropdown, it is right away.
A live character counter uses input:
const bio = document.querySelector("#bio")
const remaining = document.querySelector("#remaining")
bio.addEventListener("input", (event) => {
const left = 160 - event.target.value.length
remaining.textContent = `${left} characters left`
})Swap "input" for "change" and the counter only updates when you click away, which feels broken. Input And Change Events (opens in a new tab) has both side by side.
Handling a form submit
Listen for submit on the form, not click on the button. That way pressing Enter in a field works too. By default, submitting a form reloads the page, so call event.preventDefault() first:
const form = document.querySelector("#signup")
form.addEventListener("submit", (event) => {
event.preventDefault()
const email = form.querySelector("#email").value
console.log("Signing up", email)
})Without preventDefault(), the page reloads and your console.log disappears before you can read it. See Preventing Default (opens in a new tab).
Keyboard events
Use keydown and check event.key:
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
closeMenu()
}
})Listening on document catches the key wherever focus is on the page. event.key gives readable names like "Enter", "Escape" and "ArrowDown".
Removing a listener, or running it once
To stop listening, call removeEventListener with the same type and the same function. That means the function needs a name:
function handleClick() {
console.log("clicked")
}
button.addEventListener("click", handleClick)
button.removeEventListener("click", handleClick)If you only need it once, pass an options object instead:
button.addEventListener("click", handleClick, { once: true })The browser removes the listener after the first click.
Listening to many items at once
If a list has 50 delete buttons, you don't need 50 listeners. Put one listener on the list and check what was clicked:
const list = document.querySelector("#todos")
list.addEventListener("click", (event) => {
const button = event.target.closest(".delete")
if (!button) return
button.closest("li").remove()
})Clicks bubble up from the button to the list, so the one listener hears them all. It also works for items you add later. This is called event delegation, and Event Delegation (opens in a new tab) covers it fully.
addEventListener vs onclick
You will also see button.onclick = () => { ... }. It works, but it is a single slot: setting it again replaces the old handler. addEventListener can attach as many listeners as you want, supports options like once, and can be removed cleanly. Most modern code uses addEventListener.
Common mistakes
- Calling the function instead of passing it.
button.addEventListener("click", handleClick())runshandleClickimmediately and passes its return value, usuallyundefined. WritehandleClickwith no parentheses. - Adding
onto the event name. The event is"click", not"onclick". The wrong name doesn't throw an error. The listener just never fires. - Selecting the element before it exists. If your script runs before the HTML is parsed,
querySelectorreturnsnulland you getCannot read properties of null (reading 'addEventListener'). Load the script withdefer, or put it at the end of thebody. See Adding JavaScript To A Page (opens in a new tab). - Using
querySelectorAlllike a single element. It returns a list. Loop over it withforEach, or use delegation. - Trying to remove an anonymous function.
removeEventListenerneeds the exact same function. Two arrow functions that look identical are still different functions.
Quick recap
element.addEventListener("click", fn)runsfnevery time the event happens.- Your function gets an event object.
event.target,event.keyandevent.preventDefault()are the ones to learn first. - Use
inputfor live typing,changefor committed values, andsubmiton the form itself. - Pass the function, don't call it, and make sure the element exists first.
- One listener on a parent can handle clicks for every child.
Frequently asked questions
What does addEventListener do in JavaScript?
It tells the browser to run a function whenever a specific event happens on an element. You can attach it to buttons, inputs, forms, the document, or the window.
What is the difference between addEventListener and onclick?
onclick holds one handler, so assigning it again replaces the last one. addEventListener lets you attach several listeners to the same event, pass options, and remove a specific one later.
Why is my event listener not working?
The most common causes are calling the function instead of passing it, using "onclick" as the event name, or selecting the element before it exists on the page. Check the console for a null error first.
What is event.target?
It is the element where the event started. In a list of buttons, event.target tells you which one was clicked.
How do I remove an event listener?
Call removeEventListener with the same event type and the same named function you added. If you only want it to fire once, pass { once: true } when you add it.
Practice
The matching exercises are in the course. Start with Listening For Clicks (opens in a new tab), read live typing in Input And Change Events (opens in a new tab), then put it together in Project Product Filter (opens in a new tab). Each exercise works in your browser, so there is nothing to install.
Keep going
JavaScript DOM (opens in a new tab) takes you from your first click handler to forms, validation and event delegation. If functions and arrays still feel shaky, JavaScript Basics (opens in a new tab) is the right first step.








