The DOM, or Document Object Model, is the in-memory tree of objects that a browser builds from an HTML document and exposes through a standard programming interface, so that scripts can read, modify, add and remove elements, attributes and text while the page is running. It is defined by the WHATWG DOM Living Standard and implemented by every modern browser engine.
The DOM is not the HTML source itself. The source is text sent over the network; the DOM is the live, parsed representation of that text, corrected for errors and changed by scripts. What a developer sees in browser developer tools is the current DOM, which can differ substantially from the original HTML.
How the browser builds the DOM tree
When an HTML response arrives, the browser’s HTML parser tokenizes the markup and constructs a tree of nodes step by step. The algorithm is precisely specified, so different browsers produce the same tree from the same markup, even when the markup is invalid.
The parser repairs errors as it goes. It inserts missing html, head and body elements, closes unclosed paragraphs and moves misplaced table content. As a result, the DOM always has a well-formed tree structure, regardless of how careless the source is.
Parsing interacts with scripts. A classic script element without defer or async pauses parsing until the script is downloaded and executed, because the script might change the document. The DOMContentLoaded event fires once the tree is complete, while the load event waits for images, stylesheets and other subresources.
Node types and the structure of the tree
Every item in the DOM is a node, and nodes have types that determine what they can contain and which methods they provide. Elements are only one type among several.
| Node type | Represents | Example |
|---|---|---|
| Document | The root of the tree and entry point for scripts | The document object |
| Element | An HTML element with tag name and attributes | A p, div or button element |
| Text | Character data inside an element | The words inside a paragraph |
| Comment | An HTML comment preserved in the tree | A developer note in markup |
| DocumentFragment | A lightweight container not attached to the page | Content of a template element |
| Attr | An attribute of an element | The href value of a link |
Nodes relate as parents, children and siblings. Whitespace between tags becomes text nodes, which is why childNodes often returns more items than children, which lists element nodes only.
An important distinction exists between attributes and properties. The attribute is the value written in HTML, while the property is the current state of the object. For an input field, the value attribute holds the initial value, whereas the value property holds what the user has typed.
Working with the DOM API
The DOM API offers methods for selecting, traversing, changing and observing the tree. Most everyday work uses a small subset of them.
| Task | Common methods and properties | Note |
|---|---|---|
| Select elements | querySelector, querySelectorAll, getElementById | querySelectorAll returns a static list |
| Change content | textContent, innerHTML, replaceChildren | innerHTML parses markup and risks injection |
| Change attributes | setAttribute, classList, dataset | classList avoids string manipulation |
| Create and insert | createElement, append, before, after | Batch inserts with a fragment |
| React to events | addEventListener, removeEventListener | Events bubble up the tree |
| Observe changes | MutationObserver | Replaces deprecated mutation events |
Event propagation follows the tree. An event travels down from the document in the capture phase, reaches the target, and then bubbles back up through its ancestors. This enables event delegation: one listener on a list container can handle clicks on hundreds of list items.
Using innerHTML with untrusted data is a classic source of cross-site scripting vulnerabilities. Setting textContent inserts plain text safely, and the Trusted Types API can enforce safe handling of markup in sensitive applications.
DOM compared with related concepts
Several neighboring structures are often confused with the DOM. Distinguishing them clarifies where a change actually takes effect.
| Concept | What it is | Relationship to the DOM |
|---|---|---|
| HTML source | Markup text delivered by the server | Input from which the DOM is parsed |
| CSSOM | Object model of parsed stylesheets | Combined with the DOM to compute styles |
| Render tree | Visible nodes with computed styles | Excludes elements such as display none |
| Shadow DOM | Encapsulated subtree attached to an element | Hides internal structure of web components |
| Virtual DOM | Framework-level copy of the UI in memory | Diffed to minimize real DOM updates |
| Accessibility tree | Semantic structure for assistive technology | Derived from the DOM and ARIA attributes |
The virtual DOM used by some front-end frameworks is not part of any browser standard. It is a JavaScript data structure that a library compares between renders to decide which real DOM operations to perform.
Performance and common pitfalls
DOM operations are cheap individually but expensive in patterns. The main cost comes from forcing the browser to recalculate styles and layout repeatedly.
- Layout thrashing: alternating reads such as offsetHeight with writes such as style changes forces repeated synchronous layout; batching reads before writes avoids it.
- Very large trees: pages with many thousands of nodes slow down style calculation and memory use; common performance audits start warning at roughly 800 nodes and flag trees above about 1,400 nodes as excessive.
- Assuming the source equals the DOM: scripts and parser corrections mean that selectors must target the live tree, not the original markup.
- Memory leaks: removed nodes still referenced from JavaScript variables or listeners cannot be garbage-collected.
- Live collections: methods such as getElementsByClassName return lists that change during iteration, which can produce skipped or repeated items.
A plain-language summary
When a browser opens a web page, it reads the HTML text. Then it builds a family tree of everything on the page. Headings, paragraphs, images and buttons each become one branch of that tree. That tree is the DOM.
Programs on the page can climb this tree and change it. They can add a new message or hide a menu. The visible page updates right away. The DOM is the live version of the page, not the original text file.
An example from practice
A developer builds a task list for a project management web app. Each task is an li element inside a ul. Instead of attaching a click listener to every task, the developer adds one listener on the list and checks which item was clicked, so newly added tasks work automatically through event delegation.
When a user loads 300 tasks at once, the first version inserts each item separately and reads its height after every insertion, which freezes the page for a noticeable moment. The developer rewrites the code to build all items inside a DocumentFragment, insert them in a single operation and read sizes afterward. The list now renders without visible delay, and task text is set with textContent to prevent script injection from user input.