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.

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 matchesquerySelector()takes any CSS selector and returns the first match, ornullif nothing matches.querySelectorAll()returns every match as a NodeList, which you can loop over withforEachorfor...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 tooChanging 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:
- The selector doesn't match. A typo, a missing
#or., or a class name that's different in the HTML. - The script ran before the HTML loaded. If your
<script>tag sits in the<head>, it runs before the<body>exists. Adddeferto 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, notid="title". Use"#title"for an id and".menu"for a class. - Using
innerHTMLfor user input. Set text withtextContentinstead. - Styling with JavaScript line by line. Toggle a class with
classListand 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, andquerySelectorAll()finds them all.textContent,classListand attributes change what's on screen.addEventListener()runs your code when the user does something.createElement()andappend()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.








