Start.dev
Back to blog

What the DOM is, and how JavaScript changes a page

The DOM is the browser's live version of your HTML. Learn how JavaScript finds elements, changes text and classes, reacts to clicks and builds new ones.

Ariel Weinberger
Ariel Weinberger ยท 5 min read

What is the DOM, and how does a few lines of JavaScript change a page that's already on screen?

Short answer: the DOM, short for Document Object Model, is the browser's live, in-memory version of your HTML, organized as a tree of objects. JavaScript can find any element in that tree, read it, change it, add new ones or remove them, and the browser updates the page straight away.

By the end of this post you will know what the DOM is (and isn't), find elements with querySelector, change text, classes and attributes, react to a click, and build new elements from data. If JavaScript basics like variables and functions are still new, start with JavaScript Basics (opens in a new tab).

Your HTML becomes a tree

When the browser loads a page, it reads your HTML and builds a tree of objects from it. Each tag becomes an element node, and elements inside other elements become their children.

<body>
  <h1 id="title">Snack bar</h1>
  <ul class="menu">
    <li>Popcorn</li>
    <li>Soda</li>
  </ul>
  <button id="order">Order</button>
</body>

In the DOM, body is the parent of the h1, the ul and the button, and the ul is the parent of both li elements. JavaScript reaches the tree through one object, document.

The DOM isn't your HTML file. The file is the starting point. The DOM is what's in the browser's memory right now, so when JavaScript changes it, the page changes, but the HTML file on disk stays the same. That's why "View page source" can look different from what you see in the browser's Elements panel. What Is The Dom (opens in a new tab) walks through this with DevTools.

Find an element

Before you can change something, you have to find it.

const title = document.querySelector("#title");        // by id
const menu = document.querySelector(".menu");          // by class
const firstItem = document.querySelector(".menu li");  // any CSS selector
const items = document.querySelectorAll(".menu li");   // all matches
  • querySelector() takes any CSS selector and returns the first match, or null if nothing matches.
  • querySelectorAll() returns every match as a NodeList, which you can loop over with forEach or for...of.
  • getElementById("title") is the older way to find one element by id. Note there's no # there.

Queryselector And Getelementbyid (opens in a new tab) and Queryselectorall And Nodelists (opens in a new tab) practice both.

Change what's on the page

Once you have an element, you can change its text, its classes and its attributes:

title.textContent = "Snack bar (open)";      // change the text
 
title.classList.add("highlight");            // add a CSS class
title.classList.toggle("hidden");            // add or remove it
 
const button = document.querySelector("#order");
button.setAttribute("aria-label", "Order snacks");
button.disabled = true;                      // many attributes are properties too

Changing classes, rather than setting element.style directly, keeps your styling in CSS where it belongs. JavaScript just switches it on and off.

You'll also see innerHTML, which reads or replaces the HTML inside an element. Prefer textContent whenever you're setting plain text. innerHTML treats the string as HTML, so if any of it came from a user, they could inject markup or scripts into your page. Textcontent And Innerhtml (opens in a new tab) covers the difference.

React to the user

A page that only changes when it loads isn't very interactive. Event listeners let your code run when something happens:

const button = document.querySelector("#order");
const status = document.querySelector("#title");
 
button.addEventListener("click", () => {
  status.textContent = "Order placed!";
});

addEventListener takes the event name, like "click", "input" or "submit", and a function to run each time it happens. The function receives an event object with details, such as which element was clicked. Your First Click Handler (opens in a new tab) is the first one you'll write, and The Event Object (opens in a new tab) goes further.

Build elements from data

You can also create brand-new elements and add them to the page, which is how most apps turn data into a list or a grid of cards:

const snacks = ["Popcorn", "Soda", "Nachos"];
const list = document.querySelector(".menu");
 
list.innerHTML = "";  // clear the existing items
 
for (const snack of snacks) {
  const li = document.createElement("li");
  li.textContent = snack;
  list.append(li);
}

createElement() makes an element that isn't on the page yet. You fill it in, then append() attaches it, and only then does it appear. To take one away, call element.remove(). Creating An Element (opens in a new tab) and Rendering A List From Data (opens in a new tab) build this step by step.

The most common DOM error

Sooner or later you'll see this in the console:

TypeError: Cannot set properties of null (setting 'textContent')

It means querySelector found nothing and returned null, and then your code tried to use it. There are two usual causes:

  1. The selector doesn't match. A typo, a missing # or ., or a class name that's different in the HTML.
  2. The script ran before the HTML loaded. If your <script> tag sits in the <head>, it runs before the <body> exists. Add defer to the tag, as in <script src="app.js" defer></script>, or put the script at the end of the <body>.

The same problem with a listener reads Cannot read properties of null (reading 'addEventListener'). Adding JavaScript To A Page (opens in a new tab) covers how a script gets onto the page.

Common mistakes

  • Looping a NodeList like it's a single element. querySelectorAll(".menu li").textContent = "x" does nothing useful. Loop over the list and change each element.
  • Forgetting the selector symbol. querySelector("title") looks for a <title> tag, not id="title". Use "#title" for an id and ".menu" for a class.
  • Using innerHTML for user input. Set text with textContent instead.
  • Styling with JavaScript line by line. Toggle a class with classList and let CSS do the styling.
  • Adding a listener to elements that don't exist yet. If you build items later, attach the listener to their parent and check which child was clicked. That's called event delegation.

Quick recap

  • The DOM is the browser's live tree of objects built from your HTML.
  • querySelector() finds the first match, and querySelectorAll() finds them all.
  • textContent, classList and attributes change what's on screen.
  • addEventListener() runs your code when the user does something.
  • createElement() and append() build new elements from data.

Frequently asked questions

What is the DOM in JavaScript?

It's the Document Object Model: the browser's representation of a web page as a tree of objects. JavaScript reads and changes the page through it, starting from the document object.

Is the DOM the same as HTML?

No. HTML is the text in your file. The DOM is the live structure the browser builds from it, and JavaScript can change the DOM without touching the file.

What's the difference between querySelector and getElementById?

getElementById("title") only finds elements by id. querySelector("#title") accepts any CSS selector, so it can also find by class, tag, attribute or position. Both return one element or null.

Do I still need the DOM if I use React?

React updates the DOM for you, so you'll write less of this code by hand. Knowing how the DOM works still makes React, and its bugs, much easier to understand. Our useEffect guide shows one place they meet.

Practice

Try it in your browser, with nothing to install: What Is The Dom (opens in a new tab), then Queryselector And Getelementbyid (opens in a new tab), then Your First Click Handler (opens in a new tab). Project Product Filter (opens in a new tab) ties finding, changing and events together in one small project. For extra reps, try the JavaScript DOM Interactions challenges.

Where to go next

JavaScript DOM (opens in a new tab) picks up where JavaScript Basics (opens in a new tab) ends, and goes on to forms, validation and event delegation. If you want to tidy the data before you render it, our guide to JavaScript array methods pairs well with building lists.

Level up your coding skills

Jump into interactive courses and start building real-world projects.

Start learning

Related posts

Learn the JavaScript array methods you will use daily: map, filter, find, some, every, reduce and sort, with runnable examples on one shopping cart.
Ariel Weinberger
Ariel Weinberger ยท 5 min read
What useEffect really does, when it runs, and how the dependency array and cleanup function work. Simple examples for fetching data, timers and page titles.
Ariel Weinberger
Ariel Weinberger ยท 5 min read
A plain-English guide to JavaScript async/await: what it really does, how it relates to promises, and the mistakes that trip people up.
Ariel Weinberger
Ariel Weinberger ยท 5 min read