Understand how browsers turn your HTML into a navigable tree of objects —
and how JavaScript uses the document entry point to read and
manipulate every part of a live web page.
The Document Object Model (DOM) is a programming interface for web documents. When a browser loads an HTML page it parses the markup and builds a tree of objects — one object for every element, attribute, and piece of text. JavaScript can then use this tree to read, change, add, or remove anything on the page without reloading it.
The DOM is live — any change made through JavaScript is immediately reflected in what the user sees. This is what makes modern interactive web applications possible.
Think of the DOM as a family tree for your webpage:
<h1>, <p>,
<div>
<!-- This HTML produces the tree shown below -->
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Hello</h1>
<p>Welcome</p>
</body>
</html>
/*
Document
└── html
├── head
│ └── title ("My Page")
└── body
├── h1 ("Hello")
└── p ("Welcome")
*/
document is the invisible root that holds everythinghtml is the child of document and the parent of head and
bodyh1 and p are siblings — both children of body// document is always available in the browser
console.log(typeof document); // "object"
console.log(document.title); // page title
// Navigate to body
console.log(document.body); // the body element
// childNodes includes text nodes (spaces/line breaks too)
console.log(document.body.childNodes); // NodeList
// children — only element nodes (recommended)
console.log(document.body.children); // HTMLCollection
document.body is a direct shortcut to the <body> elementchildNodes returns all nodes including whitespace text nodes between tagschildren returns only element nodes — much cleaner for most tasks// Every node has a nodeType property:
// 1 → Element node (e.g. <div>, <p>)
// 3 → Text node (the actual text content)
// 8 → Comment node (<!-- ... -->)
// 9 → Document node (the document itself)
console.log(document.nodeType); // 9 (Document)
console.log(document.body.nodeType); // 1 (Element)
// nodeName tells you what kind of element it is
console.log(document.body.nodeName); // "BODY"
nodeType number — element nodes are 1, text
nodes are 3nodeName returns the tag name in uppercase for element nodes// Navigate up, down, and sideways through the tree
let body = document.body;
console.log(body.parentNode); // html element (parent)
console.log(body.firstElementChild); // first element child
console.log(body.lastElementChild); // last element child
console.log(body.children.length); // number of element children
// parentElement is the cleaner version of parentNode for elements
console.log(body.parentElement); // html element
parentNode / parentElement — move up one levelfirstElementChild / lastElementChild — access first or last child element
directlychildren.length — count how many direct element children a node hasThink of the DOM like a company org chart:
Click ▶ Preview, then press the button to inspect the DOM
tree live — printing the tag name, node type, and child count of every direct
child of <body>.
<!DOCTYPE html>
<html>
<head><title>DOM Structure</title></head>
<body style="font-family:sans-serif;padding:24px;background:#f8f9fa">
<h1 id="title">Hello Aman</h1>
<p id="intro">Learning DOM</p>
<button onclick="inspectDOM()"
style="margin-top:12px;padding:8px 18px;background:#f7df1e;border:none;
border-radius:6px;cursor:pointer;font-weight:700;font-size:1rem">
Inspect DOM
</button>
<div id="output"
style="margin-top:16px;font-size:0.9rem;line-height:2;
font-family:monospace;background:#1e1e2e;color:#cdd6f4;
border-radius:8px;padding:16px">
</div>
<script>
function inspectDOM() {
let info = "";
info += "document.title: <b>" + document.title + "</b><br>";
info += "document.body.nodeType: <b>" + document.body.nodeType + "</b> (Element)<br>";
info += "body.children.length: <b>" + document.body.children.length + "</b><br><br>";
info += "<b>Direct element children of <body>:</b><br>";
for (let el of document.body.children) {
info += " <" + el.tagName.toLowerCase() + ">";
if (el.id) info += " #" + el.id;
info += " → nodeType: " + el.nodeType;
info += ", children: " + el.children.length + "<br>";
}
document.getElementById("output").innerHTML = info;
}
</script>
</body>
</html>
// Open any web page and run these in DevTools console
console.log(document.body);
console.log(document.body.nodeType);
console.log(document.body.nodeName);
console.log(document.title);
nodeType is 1 (Element) and nodeName is
"BODY"document.body.parentElement — what does it return?// Compare the two collections
console.log("childNodes:", document.body.childNodes.length);
console.log("children:", document.body.children.length);
// Loop through element children only
for (let el of document.body.children) {
console.log(el.tagName);
}
childNodes is larger (includes text/whitespace nodes)children instead and loop through — confirm only element tags are listedfirstElementChild and lastElementChild of
document.bodyconsole.log(typeof document);
console.log(document.nodeType);
document is the top-level object representing the entire
HTML page. It has nodeType === 9 (Document node) and is the starting point for all DOM
traversal and selection.
console.log(document.body.childNodes.length);
console.log(document.body.children.length);
childNodes returns every node including text nodes
(whitespace, line breaks, comments). children returns only element nodes — the one you
should reach for in most situations.
Always use children instead of childNodes unless you specifically need text
nodes — whitespace between tags creates unexpected text nodes:
// childNodes includes whitespace text nodes between tags
let allNodes = document.body.childNodes;
console.log("childNodes length:", allNodes.length);
// children gives only element nodes — predictable
let elements = document.body.children;
console.log("children length:", elements.length);
// Loop safely with children
for (let el of document.body.children) {
console.log(el.tagName); // always a real tag, never a text node
}
The DOM is live — collections like children automatically update when you
add or remove elements, which can cause bugs if you're looping while modifying:
// Check child count before and after a DOM change
console.log("Before:", document.body.children.length);
let p = document.createElement("p");
p.textContent = "Dynamically added";
document.body.appendChild(p);
// The live collection updates immediately
console.log("After:", document.body.children.length);
Use document.documentElement to access the <html> root element —
distinct from document.body:
console.log(document.documentElement.nodeName); // "HTML"
console.log(document.head.nodeName); // "HEAD"
console.log(document.body.nodeName); // "BODY"
console.log(document.title); // page title string
Use browser DevTools to explore the DOM visually — the Elements panel is the live DOM tree. Right-click any element on a page and choose Inspect to navigate to it instantly.
How many child nodes does this <body> have — and how many
are element nodes? Think carefully before running.
// Imagine a page whose body looks like:
// <body>\n <h1>Hello</h1>\n</body>
// In the runner here, document.body has its own children:
console.log("childNodes:", document.body.childNodes.length);
console.log("children:", document.body.children.length);
console.log("first child nodeType:", document.body.childNodes[0]?.nodeType);
// Consider a body written as:
// <body>
// <h1>Hello</h1>
// </body>
// The newline + spaces between <body> and <h1> is a TEXT NODE
// The <h1> itself is an ELEMENT NODE (nodeType 1)
// The newline after </h1> is another TEXT NODE
// So childNodes.length may be 3:
// [0] Text node "\n " nodeType: 3
// [1] h1 element nodeType: 1
// [2] Text node "\n" nodeType: 3
// children.length is 1:
// only the <h1> — text nodes are excluded
// Key takeaway:
// childNodes counts EVERYTHING (including whitespace)
// children counts only HTML ELEMENTS
//
// The actual count varies depending on the page you run it on.
// In this runner, document.body contains the page's own elements.
// Always prefer .children when you want predictable results.