Skip to main content
Back to module
JavaScript Essentials · Working with the DOM

Event listeners

Reading39mLesson 2 of 3 in this module

Make a page react to clicks and key presses with addEventListener.

Why this matters

A page that only changes once, when it loads, is not very interactive. Real interfaces wait for the user to do something (click a button, type in a box, press Enter) and then respond. The browser announces each of these actions as an event, and your code can listen for it. Every button, form, menu and game control on the web works this way.

addEventListener

You attach a listener to an element with addEventListener(type, handler):

<button id="like">Like</button>
<span id="count">0</span>
const likeButton = document.querySelector("#like");
const countEl = document.querySelector("#count");
let likes = 0;

function handleLike() {
  likes++;
  countEl.textContent = likes;
}

likeButton.addEventListener("click", handleLike);
  • The first argument is the event type as a string: "click", "input", "keydown", "submit", "change"...
  • The second is a function the browser will call each time the event happens.

Notice handleLike has no parentheses. You are handing the function to the browser to call later. Writing handleLike() would call it once, immediately, and pass its return value (undefined) as the listener. This is the most common event bug.

Short handlers are often written inline as arrow functions:

likeButton.addEventListener("click", () => {
  likes++;
  countEl.textContent = likes;
});

The event object

The browser passes an event object to your handler with details about what happened:

input.addEventListener("keydown", (event) => {
  console.log(event.key);     // "a", "Enter", "ArrowUp", ...
  console.log(event.target);  // the element the event happened on
});

event.key tells you which key was pressed, so you can react to Enter only:

const nameInput = document.querySelector("#name");
const greeting = document.querySelector("#greeting");

nameInput.addEventListener("keydown", (event) => {
  if (event.key === "Enter") {
    greeting.textContent = `Hello, ${nameInput.value}!`;
  }
});

An input's current text is in its value property, and it is always a string.

Common event types

eventfires when
clickan element is clicked or tapped (also Enter/Space on a focused button)
inputthe value of a text box changes, on every keystroke
changea select, checkbox or text box is committed
keydowna key is pressed
submita form is submitted

Prefer click on real <button> elements over clicks on <div>s. A button can be reached with the keyboard and announced by screen readers; a clickable div cannot, unless you rebuild all of that yourself.

preventDefault

Some events have a default action: clicking a link navigates, and submitting a form reloads the page. event.preventDefault() cancels that so your code can handle it instead:

form.addEventListener("submit", (event) => {
  event.preventDefault();   // stay on this page
  // ...read the inputs and update the page
});

Event delegation

If you have many similar elements, or elements that are added later (like to-do items), you can put one listener on their parent and check event.target:

list.addEventListener("click", (event) => {
  if (event.target.matches("button.delete")) {
    event.target.closest("li").remove();
  }
});

This works because most events bubble: a click on a button inside an li inside a ul is also a click on the li and the ul. You will use this in the next lesson.

Removing a listener

removeEventListener needs the same function you added, which is one reason to give handlers names:

likeButton.removeEventListener("click", handleLike);

Common mistakes

  • Calling the handler instead of passing it. addEventListener("click", handle()) is wrong; use handle.
  • Misspelling the event type. "onclick" and "Click" silently do nothing. The type is "click".
  • Adding the listener inside a loop or another handler by accident, so it runs twice per click.
  • Forgetting that value is a string. "2" + 1 is "21"; convert with Number().
  • Clickable divs. Use <button> for anything that acts like a button.

Quick recap

  • element.addEventListener("type", handler) runs handler every time the event fires.
  • Pass the function, do not call it.
  • The event object tells you what happened: event.key, event.target.
  • preventDefault() stops default actions; delegation handles many children with one listener.

Try it

Open the Do tab: make a Like button that counts clicks, and a name box that greets the user when they press Enter.

Also in this lesson: