JavaScript DOM Navigation
The DOM (Document Object Model) represents an HTML document as a tree of nodes. DOM navigation allows you to traverse this tree, moving between parent, child, and sibling nodes to access and manipulate elements.
parentNode and parentElement
The parentNode property returns the parent of a node. parentElement is similar but returns null if the parent is not an element node (e.g., if the parent is the document).
// Given HTML: <div id="parent"><p id="child">Hello</p></div>
// const child = document.getElementById('child');
// const parent = child.parentNode;
// console.log(parent.id); // 'parent'
// parentNode vs parentElement
// document.documentElement.parentNode -> #document
// document.documentElement.parentElement -> null
// Simulating DOM navigation
const dom = {
tag: 'div', id: 'parent',
children: [
{ tag: 'p', id: 'child', text: 'Hello', parent: 'div#parent' }
]
};
console.log('Child: ' + dom.children[0].tag + '#' + dom.children[0].id);
console.log('Parent: ' + dom.children[0].parent);
console.log('parentNode returns any node type');
console.log('parentElement returns only element nodes');childNodes and children
childNodes returns ALL child nodes (including text and comment nodes). children returns only element child nodes. Use children for most practical purposes.
// HTML: <ul id="list"><li>One</li><li>Two</li><li>Three</li></ul>
// const list = document.getElementById('list');
// console.log(list.childNodes.length); // May include text nodes
// console.log(list.children.length); // Only element nodes
// Simulating children access
const listChildren = ['One', 'Two', 'Three'];
console.log('children.length: ' + listChildren.length);
listChildren.forEach(function(item, index) {
console.log('Child ' + index + ': ' + item);
});
console.log('\nchildNodes includes text/comment nodes');
console.log('children includes only element nodes');firstChild, lastChild, firstElementChild, lastElementChild
firstChild/lastChild return the first/last child node (any type). firstElementChild/lastElementChild return only element nodes, skipping text and comment nodes.
// HTML: <div id="box"> <span>First</span> <span>Last</span> </div>
// const box = document.getElementById('box');
// box.firstChild -> text node (whitespace)
// box.firstElementChild -> <span>First</span>
// box.lastChild -> text node (whitespace)
// box.lastElementChild -> <span>Last</span>
const elements = ['Header', 'Content', 'Footer'];
console.log('firstElementChild: ' + elements[0]);
console.log('lastElementChild: ' + elements[elements.length - 1]);
console.log('\nfirstChild may return whitespace text nodes');
console.log('firstElementChild always returns an element');nextSibling and previousSibling
nextSibling/previousSibling return the next/previous node (any type). nextElementSibling/previousElementSibling return only element siblings.
// HTML: <p>First</p> <p id="middle">Middle</p> <p>Last</p>
// const middle = document.getElementById('middle');
// middle.previousElementSibling -> <p>First</p>
// middle.nextElementSibling -> <p>Last</p>
// Simulating sibling navigation
const siblings = ['First', 'Middle', 'Last'];
const currentIndex = 1; // 'Middle'
console.log('Current: ' + siblings[currentIndex]);
console.log('Previous sibling: ' + siblings[currentIndex - 1]);
console.log('Next sibling: ' + siblings[currentIndex + 1]);
// Walking through all siblings
console.log('\nAll siblings:');
siblings.forEach(function(s) {
console.log(' - ' + s);
});Node Types
Every DOM node has a nodeType property that identifies its type. Understanding node types helps when navigating and filtering nodes.
| nodeType | Constant | Description |
|---|---|---|
| 1 | ELEMENT_NODE | HTML element (<p>, <div>, etc.) |
| 2 | ATTRIBUTE_NODE | Element attribute (deprecated) |
| 3 | TEXT_NODE | Text content |
| 8 | COMMENT_NODE | HTML comment |
| 9 | DOCUMENT_NODE | The document itself |
| 11 | DOCUMENT_FRAGMENT_NODE | A lightweight document |
// Checking node types
// const el = document.getElementById('test');
// console.log(el.nodeType); // 1 (Element)
// console.log(el.nodeName); // 'DIV'
// console.log(el.nodeValue); // null (for elements)
// Filtering only element nodes from childNodes
// const elementChildren = [];
// for (let i = 0; i < parent.childNodes.length; i++) {
// if (parent.childNodes[i].nodeType === 1) {
// elementChildren.push(parent.childNodes[i]);
// }
// }
const nodeTypes = {
1: 'Element',
3: 'Text',
8: 'Comment',
9: 'Document'
};
Object.keys(nodeTypes).forEach(function(type) {
console.log('nodeType ' + type + ': ' + nodeTypes[type]);
});