Learn / Programming / JavaScript / The DOM and Events

Intermediate 14 min

The DOM and Events

Select elements, react to clicks and update the page.

What you will learn

  • Query the DOM
  • Add event listeners
  • Update text and classes

When a browser loads an HTML page it builds the DOM (Document Object Model), a tree of objects representing every element. JavaScript can read and change that tree, which is how pages become interactive. Everything starts from the global document object.

const title = document.querySelector("h1");        // first match
const items = document.querySelectorAll(".item");  // all matches
const byId  = document.getElementById("save");

querySelector takes any CSS selector, so you already know the syntax. It returns null if nothing matches, so check before using the result.

title.textContent = "Welcome back";
title.classList.add("highlight");
title.classList.toggle("hidden");
title.setAttribute("data-state", "ready");
title.style.color = "tomato";

Prefer textContent over innerHTML for plain text. Setting innerHTML with user-supplied text opens the door to cross-site scripting (XSS) attacks. Prefer toggling CSS classes over setting inline styles.

Events

An event listener runs a function when something happens: a click, a key press, a form submit. The function receives an event object describing what occurred.

const button = document.querySelector("#save");
let clicks = 0;
button.addEventListener("click", (event) => {
  clicks += 1;
  button.textContent = `Saved ${clicks} times`;
});

const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
  e.preventDefault();               // stop the page reload
  console.log(new FormData(form).get("email"));
});
const li = document.createElement("li");
li.textContent = "New task";
document.querySelector("ul").append(li);

Event delegation

Instead of attaching a listener to every list item, attach one to the parent and inspect event.target. It works for items added later, and uses less memory.

document.querySelector("ul").addEventListener("click", (e) => {
  const li = e.target.closest("li");
  if (li) li.classList.toggle("done");
});
Timing

Scripts placed in the <head> run before the elements exist. Add defer to the script tag, or place it at the end of <body>.

Try it yourself

Build a counter: a button that increments a number shown on the page each time it is clicked, plus a reset button.

Show solution
// HTML: <p id="n">0</p> <button id="inc">+1</button> <button id="reset">Reset</button>
let n = 0;
const out = document.querySelector("#n");
document.querySelector("#inc").addEventListener("click", () => {
  out.textContent = ++n;
});
document.querySelector("#reset").addEventListener("click", () => {
  n = 0;
  out.textContent = n;
});