The HTML DOM

Your HTML is the blueprint. The DOM is the building.

The browser reads HTML once, then builds a live, in-memory tree of objects from it — the Document Object Model. JavaScript talks to that tree, not to the original text file, which is why a page can change after it loads without anyone editing the source.

From markup to tree

Every tag becomes a node, nested the same way it was nested in the HTML. Text inside a tag becomes its own node too. This nested structure is what "Document Object Model" actually refers to.

  • document
    • <html>
      • <head>
        • <title>
          • "Trail Notes"
      • <body>
        • <h1>
          • "Trail Notes"
        • <p>
          • "It rained the whole way."

Try it — the DOM, live

This list isn't written in the page's HTML — JavaScript built every item by talking to the DOM after the page loaded. Add an item, then remove one. The panel on the right shows three different views of the same change: the JavaScript that ran, the actual HTML the browser now holds in memory, and how it looks rendered.

Live controls

    Waiting for an action…
    
            
    
            

    What's important to be aware of

    The DOM is forgiving to play with, but a few habits separate code that works from code that breaks in subtle ways.

    1
    The DOM and your HTML file are not the same thing

    Once JavaScript changes the DOM, "View page source" still shows the original file — it never updates. To see the live tree, use the browser's "Inspect" or DevTools panel instead, which reads the DOM, not the source.

    2
    Scripts can run before the page exists

    If a <script> tag runs before the elements below it have loaded, document.getElementById(...) returns null — calling a method on it throws an error. Either place scripts at the end of <body>, or wrap the code in a DOMContentLoaded listener.

    3
    Querying the DOM repeatedly is slow

    Each call to querySelector or getElementById searches the tree. In a loop, that adds up. Save the element to a variable once, then reuse the variable.

    4
    innerHTML can open the door to injected code

    Setting innerHTML with text that came from a user — a form field, a URL parameter — lets that text be parsed as HTML, including scripts. Use textContent for plain text, and only use innerHTML with content you trust or have sanitised.

    5
    Removing an element doesn't remove its event listeners from memory

    If you keep a reference to a removed node and re-add listeners to it later, you can end up with duplicate handlers firing. Remove listeners you no longer need, or rebuild elements fresh rather than reusing detached ones.

    Core vocabulary

    The handful of terms that show up in almost every DOM tutorial.

    node

    The generic name for anything in the tree — an element, a piece of text, even a comment. Elements are the most common kind of node.

    element

    A node that came from an HTML tag, like <div> or <p>. Has attributes, children, and a tag name.

    parent / child / sibling

    Relationships between nodes, mirroring how the tags were nested in the original HTML. A <li> inside a <ul> is the ul's child; two <li>s next to each other are siblings.

    event

    A signal the DOM fires when something happens — a click, a keypress, the page finishing loading. JavaScript "listens" for events and runs code in response.

    querySelector / getElementById

    Methods for finding a specific node in the tree, using a CSS-style selector or a unique id, so you can read or change it.

    createElement / appendChild

    Methods for building a brand-new node and inserting it into the tree — this is how JavaScript adds content to a page after it has loaded.