The DOM & EventsIntermediate9 min09 / 12

The DOM

Learn how the browser turns your HTML into a live tree of objects that JavaScript can read, update, and style on the fly.

You have written HTML. You have styled it with CSS. But so far your pages sit still — same text, same colours, every single load. JavaScript changes that. The moment a browser parses your HTML, it converts every element, every piece of text, and every attribute into a live object in memory. That living data structure is called the Document Object Model, or the DOM. Once you can reach into the DOM with JavaScript, your pages can respond to users, update content without reloading, and come alive in ways that plain HTML never could.

Think of it like

Think of a family tree

Your HTML is a family tree. <html> is the great-grandparent at the top. Inside it are two children: <head> and <body>. Inside <body> there might be an <h1>, a <p>, a <ul> with several <li> children, and so on. Every element is a node — a box in that tree — and JavaScript can walk up, down, or sideways through the whole family. When you write document in JavaScript, you hold a reference to the root of this tree — the entire page.

#Finding Elements: querySelector and querySelectorAll

Both methods accept any CSS selector — #id, .class, element, [attr], or combinations
// querySelector returns the FIRST match
const title = document.querySelector('#title');
console.log(title.tagName); // "H1"

// querySelectorAll returns ALL matches as a NodeList
const items = document.querySelectorAll('.item');
console.log(items.length); // 3

#Reading and Changing Text

textContent reads or replaces the plain text inside any element — no HTML tags involved
const title = document.querySelector('#title');

console.log(title.textContent); // "Hello, world"

title.textContent = 'Hello, DOM!';
console.log(title.textContent); // "Hello, DOM!"
Common mistake

innerHTML: powerful, but handle with care

innerHTML lets you set HTML markup as a string — great for inserting <strong>bold</strong> or entire chunks of structure. But never put user-supplied text into innerHTML without sanitising it first. A malicious string could inject a <script> tag and run arbitrary code. When you only need text, always prefer textContent. Use innerHTML only when you need real HTML and you fully control the content.

#Toggling Classes with classList

Keep visual states in CSS; let JavaScript only add or remove class names. add / remove / toggle / contains are the four methods you will reach for constantly.
const card = document.querySelector('.card');

card.classList.add('highlight');      // add a class
card.classList.remove('highlight');   // remove it
card.classList.toggle('highlight');   // add if absent, remove if present

console.log(card.classList.contains('highlight')); // true or false

#Reading and Changing Attributes

getAttribute reads any attribute; setAttribute sets or creates it — works on src, alt, disabled, data-* and more
const link = document.querySelector('a');

console.log(link.getAttribute('href')); // "https://example.com"

link.setAttribute('href', 'https://mozilla.org');
link.setAttribute('target', '_blank');  // open in new tab

#Looping Over Multiple Elements

querySelectorAll returns a NodeList; call forEach on it to visit each match in order
const items = document.querySelectorAll('.item');

// NodeList supports forEach just like an array
items.forEach((item, index) => {
  item.textContent = `${index + 1}. ${item.textContent}`;
});
// Produces: "1. Apples", "2. Bananas", "3. Cherries"
Quick check

You want to add the CSS class 'active' to a button if it does not already have it, and remove it if it does — in a single call. Which method does this?

Key takeaways

  • The DOM is the browser's live, in-memory representation of your HTML as a tree of nodes — JavaScript can read and change it at any time.
  • document.querySelector(selector) finds the first match; querySelectorAll finds all matches, using the same syntax as CSS selectors.
  • Use textContent to safely read or replace text; use innerHTML only when you need real HTML markup and you control the content.
  • classList.add / remove / toggle keeps visual logic in CSS — JavaScript just switches classes on and off.
  • getAttribute and setAttribute let you read and update any HTML attribute, from href and src to disabled and custom data attributes.
Practice challenges
Test yourself · earn XP
0/4
Predict the output#1

The lesson shows that querySelectorAll returns a NodeList of every match, and that forEach visits each one in order. Given this list, what gets logged?

predict-output
// HTML: <ul>
//   <li class="item">Apples</li>
//   <li class="item">Bananas</li>
//   <li class="item">Cherries</li>
// </ul>

const items = document.querySelectorAll('.item');
console.log(items.length);
console.log(items[0].textContent);
Fix the bug#2

This code is meant to add a 'highlight' class to the card without disturbing its existing classes. It has a bug — what's wrong?

fix-bug
// HTML: <div class="card rounded"></div>

const card = document.querySelector('.card');
card.setAttribute('class', 'highlight');
console.log(card.className); // wanted: "card rounded highlight"
Fill in the blank#3

Complete this snippet. Select the single element whose id is 'title', then safely replace its plain text with 'Hello, DOM!'. Fill in the method that finds the first match and the property that reads or replaces text.

const title = document.('#title');
title. = 'Hello, DOM!';
Reorder the lines#4

Put these lines in order to select an anchor, swap its href to a new URL, and then read the new value back. The steps should run in a sensible top-to-bottom sequence.

1
link.setAttribute('href', 'https://mozilla.org');
2
console.log(link.getAttribute('href'));
3
link.setAttribute('target', '_blank');
4
console.log(link.getAttribute('href'));
5
const link = document.querySelector('a');
Your turn
Practice exercise

You have a profile card with a name heading, a bio paragraph, and an avatar image. Write JavaScript that: (1) changes the heading text to your own name, (2) adds the CSS class 'featured' to the card element, (3) updates the image's alt attribute to describe the avatar, and (4) loops over all paragraph elements inside the card and prepends the text 'Bio: ' to each one.

Try it live — edit the code and hit Run to see the output:

solution.js · editable