Skip to content

The DOM Tree

beginner12 min read

Your HTML Is Not the DOM

Here's something that trips up a surprising number of developers: the HTML you write and the DOM the browser uses are not the same thing. Your HTML file is just a text document — a set of instructions. The browser reads those instructions, parses them, and builds a tree-shaped data structure in memory called the Document Object Model. That tree is what you actually interact with when you write JavaScript.

Think about it this way. When you type document.querySelector('h1'), you're not searching through a text file. You're navigating a live tree of JavaScript objects. Change one of those objects, and the page updates in real-time. That's the magic of the DOM.

Mental Model

Imagine your HTML as a blueprint for a house. The blueprint says "put a kitchen here, a bedroom there." The browser is the construction crew that reads the blueprint and builds the actual house — the DOM. Once the house is built, you don't modify the blueprint to change the house. You walk inside and move furniture, repaint walls, add rooms. The DOM is the house. JavaScript is you, walking around making changes.

How the Browser Builds the DOM

When a browser receives an HTML document, it doesn't just slap it on screen. It runs a multi-step process called parsing that converts raw text into a structured tree.

Here's a simple HTML document and the tree the browser builds from it:

<!DOCTYPE html>
<html>
  <head>
    <title>My Page</title>
  </head>
  <body>
    <h1>Hello</h1>
    <p>Welcome to the DOM.</p>
  </body>
</html>

The browser creates a tree structure like this:

document
  └── html
        ├── head
        │     └── title
        │           └── "My Page" (text)
        └── body
              ├── h1
              │     └── "Hello" (text)
              └── p
                    └── "Welcome to the DOM." (text)

Every tag becomes a node in the tree. Every piece of text becomes a node too. Even comments and the doctype are nodes. This tree is the DOM.

Quiz
What is the DOM?

Nodes vs Elements

This is one of the most common sources of confusion, so let's clear it up right now.

Everything in the DOM tree is a node. But not every node is an element. There are several types of nodes:

Node TypenodeType ValueExample
Element1<div>, <p>, <h1>
Text3The text "Hello" inside an <h1>
Comment8<!-- a comment -->
Document9The document object itself
DocumentType10<!DOCTYPE html>
DocumentFragment11Created with document.createDocumentFragment()

Elements are the nodes that correspond to HTML tags. They're the ones with tag names, attributes, and CSS styles. Text nodes are just the raw text content between tags.

const heading = document.querySelector('h1');

heading.nodeType;   // 1 (Element)
heading.nodeName;   // "H1"

heading.firstChild.nodeType;   // 3 (Text)
heading.firstChild.nodeName;   // "#text"
heading.firstChild.nodeValue;  // "Hello"
Common Trap

Whitespace in your HTML creates text nodes too. If you have a line break or spaces between tags, the browser creates a text node for that whitespace. This is why element.childNodes often has more items than you expect, and why element.children (which only returns element nodes) is usually what you want.

const body = document.body;

// childNodes includes ALL nodes — elements, text, comments
console.log(body.childNodes.length);  // might be 5 (includes whitespace text nodes)

// children includes only element nodes
console.log(body.children.length);    // 2 (just h1 and p)
Quiz
Given this HTML: <ul> <li>One</li> <li>Two</li> </ul> — how many childNodes does the ul element have?

The document Object

The document object is your entry point to the entire DOM. It's the root of the tree, and it provides methods to find, create, and manipulate nodes.

// The document is the root
document.nodeType;    // 9 (Document)
document.nodeName;    // "#document"

// Access key elements directly
document.documentElement;  // the <html> element
document.head;             // the <head> element
document.body;             // the <body> element
document.title;            // the page title (read/write!)

// Change the page title
document.title = "New Title";
document vs window

document represents the DOM tree — the content of the page. window represents the browser tab — it includes the DOM (window.document) but also things like location, history, localStorage, setTimeout, and the global scope for JavaScript. When you write document.querySelector(...), you're technically calling window.document.querySelector(...).

DOM vs HTML: Why They Differ

The DOM and your HTML source code often don't match. Here are the common reasons:

The browser fixes invalid HTML

<!-- Your HTML (missing closing tag, no tbody) -->
<table>
  <tr><td>Cell</td></tr>
</table>
// The DOM the browser actually builds
// (browser auto-inserts <tbody>)
document.querySelector('tbody'); // exists, even though you never wrote it

JavaScript modifies the DOM

const div = document.createElement('div');
div.textContent = 'Added by JS';
document.body.appendChild(div);
// This <div> exists in the DOM but not in your HTML source

Browser extensions inject elements

Ad blockers, password managers, and other extensions add and remove DOM nodes that don't exist in your HTML.

Key Rules
  1. 1The DOM is a live tree of objects — not the HTML file itself
  2. 2Every DOM entity is a node, but only HTML tags become element nodes (nodeType 1)
  3. 3Whitespace in HTML creates text nodes — use children instead of childNodes to skip them
  4. 4The browser fixes invalid HTML when building the DOM, so the tree may differ from your source
  5. 5document is the root node and entry point to the entire tree
Quiz
You write an HTML table without a tbody element. What does document.querySelector('tbody') return?
How the HTML parser handles errors

Unlike most programming languages, HTML parsing never fails. There's no such thing as a "syntax error" in HTML. The HTML spec defines exactly how the parser should handle every kind of broken markup — missing closing tags, misnested elements, stray end tags, duplicate attributes. This is called the parser error-handling algorithm, and it's one of the most complex parts of the HTML specification. Browsers spent years converging on the same error-handling behavior so that broken HTML renders consistently everywhere. That's why document.querySelector('tbody') works even without writing one — the spec says "if you see a tr directly inside a table, auto-insert a tbody."

Inspecting the DOM

The best way to understand the DOM is to inspect it. Every browser's DevTools has an Elements panel (or Inspector in Firefox) that shows you the live DOM tree — not your HTML source.

// Quick ways to inspect the DOM from your console
console.dir(document.body);       // shows all properties as an object
console.log(document.body);       // shows as HTML markup

// Count all elements on the page
document.querySelectorAll('*').length;

// Find the deepest nesting level
function maxDepth(node, depth = 0) {
  if (!node.children.length) return depth;
  return Math.max(
    ...Array.from(node.children).map(child => maxDepth(child, depth + 1))
  );
}
maxDepth(document.body);
What developers doWhat they should do
Using innerHTML to read the DOM structure
innerHTML serializes the DOM back to an HTML string, which loses information about the live object properties, event listeners, and actual node structure
Using DevTools Elements panel or console.dir()
Assuming document.childNodes[0] is the html element
document.childNodes[0] is usually the DOCTYPE node (nodeType 10). The html element is document.documentElement — always use the named property
Using document.documentElement to access the html element
Treating the DOM like a static snapshot
The DOM is a living tree. Adding, removing, or modifying nodes instantly reflects on screen. Other scripts and browser extensions can modify it too
Understanding the DOM is live and changes in real-time
1/11