HTMLCollection vs NodeListDOM query methods return collections of nodes represented as either an HTMLCollection or a NodeList. Understanding whether a collection is live or static prevents infinite loop bugs and unexpected DOM state errors.
flowchart TD
Collection["DOM Collections"] --> HTMLColl["HTMLCollection (getElementsByTagName, getElementsByClassName)"]
Collection --> NodeListColl["NodeList (querySelectorAll, childNodes)"]
HTMLColl --> HLive["ALWAYS Live (Reflects real-time DOM changes)"]
NodeListColl --> NStatic["Static (querySelectorAll) or Live (childNodes)"]
| Feature | HTMLCollection |
NodeList |
|---|---|---|
| Returned By | getElementsByClassName, children |
querySelectorAll, childNodes |
| Contains | Element Nodes ONLY | Element Nodes, Text Nodes, Comments |
| Live / Static Status | Always Live | Static (querySelectorAll) / Live (childNodes) |
Native .forEach() |
No (Requires Array conversion) | Yes |
| Array Conversion | Array.from(collection) |
Array.from(nodeList) |
// Demonstrating Live HTMLCollection vs Static NodeList
document.addEventListener("DOMContentLoaded", () => {
const container = document.createElement("div");
container.innerHTML = `<div class="item">Item 1</div><div class="item">Item 2</div>`;
document.body.appendChild(container);
// Live Collection
const liveCollection = container.getElementsByClassName("item");
// Static Collection
const staticNodeList = container.querySelectorAll(".item");
console.log(`Initial Live Count: ${liveCollection.length}`); // 2
console.log(`Initial Static Count: ${staticNodeList.length}`); // 2
// Appending a new matching element dynamically to DOM
const newItem = document.createElement("div");
newItem.className = "item";
newItem.textContent = "Item 3";
container.appendChild(newItem);
// Live collection updates automatically! Static collection stays snapshot-frozen!
console.log(`Updated Live Count: ${liveCollection.length}`); // 3 (Updated!)
console.log(`Updated Static Count: ${staticNodeList.length}`); // 2 (Frozen!)
});
HTMLCollection with a standard for loop while inserting matching elements creates an infinite loop because collection.length increases on every pass.Array.from(collection) or spread [...collection] to use array methods (map, filter, reduce).HTMLCollection Lacks .forEach(): Calling HTMLCollection.forEach() throws a TypeError.Why does document.getElementsByTagName("div").forEach(...) throw a TypeError?
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.