Navigating the DOM
The DOM (Document Object Model) is like a family tree for web pages—elements have parents, children, and siblings. JavaScript lets you move through this structure to find, modify, or remove elements easily.
.parentNode, .childNodes, .children
Every element in the DOM knows who its parent is. You can access it using .parentNode
:
const item = document.querySelector('.list-item');
const parent = item.parentNode;
This gets the element that contains the current one.
To go downward instead of up, we use .childNodes
or .children
.
.childNodes
gives you everything—elements, text nodes (like whitespace), and comments..children
gives you only the element nodes—just the HTML tags, no text.
const list = document.querySelector('ul');
console.log(list.childNodes); // Might include text nodes
console.log(list.children); // Only actual <li> elements
Use .children
when you’re working with HTML structure and want to skip over things like whitespace or line breaks.
.firstChild, .lastChild
Need to grab the first or last thing inside an element? These do the trick:
const container = document.querySelector('.box');
const first = container.firstChild;
const last = container.lastChild;
But again, like .childNodes
, this includes everything, even empty text nodes.
If you want only the first or last element, use:
const firstEl = container.firstElementChild;
const lastEl = container.lastElementChild;
These are cleaner when you're only dealing with HTML elements and not interested in text or comment nodes.
.previousSibling, .nextSibling
DOM elements can also look left and right—to their neighbors:
const current = document.querySelector('.active');
const next = current.nextSibling;
const prev = current.previousSibling;
But again, these include any node type, not just elements. If your HTML has line breaks or spaces between elements, those count as text nodes.
For only elements, use:
const nextEl = current.nextElementSibling;
const prevEl = current.previousElementSibling;
These ignore text and go straight to the real content.
Understanding NodeLists and HTMLCollections
When you use methods like .childNodes
or .children
, or even document.querySelectorAll
, you get special array-like objects:
.childNodes
→ returns a NodeList.children
→ returns an HTMLCollectionquerySelectorAll()
→ returns a NodeList
Both of these look like arrays, but they’re not exactly the same.
HTMLCollection is live. It updates automatically if the DOM changes.
NodeList can be live or static. For example:
childNodes
→ livequerySelectorAll()
→ static
To loop through them, you can use for...of
:
for (let child of container.children) {
console.log(child.tagName);
}
Or convert to a real array if you need array methods like .map()
or .filter()
:
const kids = Array.from(container.children);
kids.forEach(el => console.log(el.tagName));
Knowing how these collections behave helps avoid weird bugs, especially when elements are added or removed on the fly.