HTML DOM Collection
Working with groups of HTML elements in JavaScript
📚 What are DOM Collections?
DOM collections are array-like objects that contain multiple HTML elements. They're returned by methods that find multiple elements at once.
// Get a collection of elements
let paragraphs = document.getElementsByTagName("p");
console.log(paragraphs.length); // Number of paragraphs
console.log(paragraphs[0]); // First paragraph
Output:
5
[object HTMLParagraphElement]
Types of Collections
HTMLCollection
Live collection that updates automatically
getElementsByTagName()
getElementsByClassName()
children
NodeList
Can be live or static collection
querySelectorAll()
childNodes
Live Collections
Update when DOM changes
getElementsByClassName()
children
Static Collections
Snapshot that doesn't change
querySelectorAll()
🔹 Getting Collections
Different methods return different types of collections:
// HTMLCollection (live)
let divsByTag = document.getElementsByTagName("div");
let divsByClass = document.getElementsByClassName("container");
let formElements = document.forms; // All forms
let imageElements = document.images; // All images
let linkElements = document.links; // All links
// NodeList (static)
let divsQuery = document.querySelectorAll("div");
let specificDivs = document.querySelectorAll("div.container");
// NodeList (live)
let allNodes = document.body.childNodes; // Includes text nodes
// HTMLCollection (live) - only elements
let allElements = document.body.children; // Only element nodes
console.log("Divs by tag:", divsByTag.length);
console.log("Divs by class:", divsByClass.length);
console.log("Divs by query:", divsQuery.length);
console.log("All forms:", formElements.length);
// Check collection type
console.log(divsByTag.constructor.name); // HTMLCollection
console.log(divsQuery.constructor.name); // NodeList
Output:
Divs by tag: 8
Divs by class: 3
Divs by query: 8
All forms: 1
HTMLCollection
NodeList
🔹 Accessing Collection Items
Different ways to access elements in collections:
let paragraphs = document.getElementsByTagName("p");
// Access by index (like arrays)
let firstP = paragraphs[0];
let secondP = paragraphs[1];
let lastP = paragraphs[paragraphs.length - 1];
// Access by name or id (HTMLCollection only)
let namedP = paragraphs.namedItem("myParagraph"); // By id or name attribute
let namedP2 = paragraphs["myParagraph"]; // Shorthand
// Using item() method
let thirdP = paragraphs.item(2);
// Check if collection is empty
if (paragraphs.length > 0) {
console.log("Found", paragraphs.length, "paragraphs");
console.log("First paragraph:", firstP.textContent);
} else {
console.log("No paragraphs found");
}
// Safe access with bounds checking
function getElementSafely(collection, index) {
if (index >= 0 && index < collection.length) {
return collection[index];
}
return null;
}
let safeParagraph = getElementSafely(paragraphs, 10);
console.log(safeParagraph); // null if index out of bounds
Output:
Found 5 paragraphs
First paragraph: This is the first paragraph
null
🔹 Iterating Through Collections
Different ways to loop through DOM collections:
let buttons = document.getElementsByTagName("button");
// Method 1: Traditional for loop
for (let i = 0; i < buttons.length; i++) {
console.log("Button", i + 1, ":", buttons[i].textContent);
buttons[i].style.margin = "5px";
}
// Method 2: for...of loop (modern, recommended)
for (let button of buttons) {
console.log("Button text:", button.textContent);
button.addEventListener("click", function() {
alert("Button clicked: " + this.textContent);
});
}
// Method 3: Convert to array first (for more array methods)
let buttonArray = Array.from(buttons);
buttonArray.forEach(function(button, index) {
console.log(`Button ${index}:`, button.textContent);
button.classList.add("processed");
});
// Method 4: Using spread operator
let buttonArray2 = [...buttons];
buttonArray2.map(button => button.textContent)
.forEach(text => console.log("Text:", text));
// Method 5: forEach (NodeList only, not HTMLCollection)
let divs = document.querySelectorAll("div");
divs.forEach(function(div, index) {
console.log(`Div ${index}:`, div.className);
});
// Filter collections (convert to array first)
let visibleButtons = Array.from(buttons).filter(button => {
return button.style.display !== "none";
});
console.log("Visible buttons:", visibleButtons.length);
Output:
Button 1 : Click Me
Button 2 : Submit
Button 3 : Cancel
Button text: Click Me
Button text: Submit
Button text: Cancel
Button 0: Click Me
Button 1: Submit
Button 2: Cancel
Text: Click Me
Text: Submit
Text: Cancel
Div 0: container
Div 1: sidebar
Visible buttons: 3
🔹 Live vs Static Collections
Understanding the difference between live and static collections:
// Live HTMLCollection - updates automatically
let liveCollection = document.getElementsByClassName("dynamic");
console.log("Initial count:", liveCollection.length); // 2
// Static NodeList - snapshot at time of creation
let staticCollection = document.querySelectorAll(".dynamic");
console.log("Static count:", staticCollection.length); // 2
// Add a new element with the class
let newDiv = document.createElement("div");
newDiv.className = "dynamic";
newDiv.textContent = "New dynamic element";
document.body.appendChild(newDiv);
// Check counts after adding element
console.log("Live count after adding:", liveCollection.length); // 3 (updated!)
console.log("Static count after adding:", staticCollection.length); // 2 (unchanged)
// Remove an element
let firstDynamic = document.querySelector(".dynamic");
firstDynamic.remove();
console.log("Live count after removing:", liveCollection.length); // 2 (updated!)
console.log("Static count after removing:", staticCollection.length); // 2 (unchanged)
// Be careful with live collections in loops!
let items = document.getElementsByClassName("item");
// WRONG - can cause infinite loop or skip elements
// for (let i = 0; i < items.length; i++) {
// items[i].className = "processed"; // Removes from collection!
// }
// CORRECT - loop backwards or convert to array
for (let i = items.length - 1; i >= 0; i--) {
items[i].className = "processed";
}
// OR convert to array first
Array.from(items).forEach(item => {
item.className = "processed";
});
Output:
Initial count: 2
Static count: 2
Live count after adding: 3
Static count after adding: 2
Live count after removing: 2
Static count after removing: 2
🔹 Collection Methods and Properties
Useful methods and properties for working with collections:
let elements = document.getElementsByTagName("div");
// Basic properties
console.log("Length:", elements.length);
console.log("Constructor:", elements.constructor.name);
// HTMLCollection specific methods
console.log("Item at index 0:", elements.item(0));
console.log("Named item:", elements.namedItem("myDiv"));
// Check if collection has elements
function hasElements(collection) {
return collection && collection.length > 0;
}
if (hasElements(elements)) {
console.log("Collection has elements");
}
// Convert collection to array for more methods
let elementArray = Array.from(elements);
// Now you can use array methods
let filteredElements = elementArray.filter(el => el.className.includes("active"));
let elementTexts = elementArray.map(el => el.textContent);
let hasSpecificElement = elementArray.some(el => el.id === "special");
console.log("Filtered elements:", filteredElements.length);
console.log("Element texts:", elementTexts);
console.log("Has special element:", hasSpecificElement);
// Find specific elements in collection
function findInCollection(collection, predicate) {
for (let i = 0; i < collection.length; i++) {
if (predicate(collection[i])) {
return collection[i];
}
}
return null;
}
let redElement = findInCollection(elements, el =>
el.style.color === "red"
);
// Count elements matching criteria
function countMatching(collection, predicate) {
let count = 0;
for (let element of collection) {
if (predicate(element)) {
count++;
}
}
return count;
}
let hiddenCount = countMatching(elements, el =>
el.style.display === "none"
);
Output:
Length: 8
Constructor: HTMLCollection
Item at index 0: [object HTMLDivElement]
Named item: [object HTMLDivElement]
Collection has elements
Filtered elements: 2
Element texts: ["Header", "Content", "Sidebar", "Footer"]
Has special element: true
🔹 Practical Examples
Real-world examples of working with DOM collections:
// Example 1: Style all elements of a type
function styleAllButtons() {
let buttons = document.getElementsByTagName("button");
for (let button of buttons) {
button.style.padding = "10px 20px";
button.style.borderRadius = "5px";
button.style.border = "none";
button.style.backgroundColor = "#007cba";
button.style.color = "white";
button.style.cursor = "pointer";
}
}
// Example 2: Add event listeners to multiple elements
function addClickHandlers() {
let links = document.getElementsByTagName("a");
Array.from(links).forEach((link, index) => {
link.addEventListener("click", function(event) {
console.log(`Link ${index + 1} clicked:`, this.href);
// Add analytics tracking here
});
});
}
// Example 3: Form validation for multiple inputs
function validateForm() {
let inputs = document.querySelectorAll("input[required]");
let isValid = true;
inputs.forEach(input => {
if (input.value.trim() === "") {
input.style.borderColor = "red";
isValid = false;
} else {
input.style.borderColor = "#ccc";
}
});
return isValid;
}
// Example 4: Image gallery with lazy loading
function setupImageGallery() {
let images = document.querySelectorAll("img[data-src]");
let imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
let img = entry.target;
img.src = img.dataset.src;
img.classList.remove("lazy");
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
}
// Example 5: Table row highlighting
function setupTableHighlighting() {
let rows = document.querySelectorAll("table tr");
rows.forEach(row => {
row.addEventListener("mouseenter", function() {
this.style.backgroundColor = "#f0f0f0";
});
row.addEventListener("mouseleave", function() {
this.style.backgroundColor = "";
});
});
}
// Example 6: Accordion functionality
function setupAccordion() {
let headers = document.querySelectorAll(".accordion-header");
headers.forEach(header => {
header.addEventListener("click", function() {
let content = this.nextElementSibling;
let isOpen = content.style.display === "block";
// Close all other accordions
document.querySelectorAll(".accordion-content").forEach(c => {
c.style.display = "none";
});
// Toggle current accordion
content.style.display = isOpen ? "none" : "block";
});
});
}
Usage:
// Call these functions to set up functionality
styleAllButtons();
addClickHandlers();
setupImageGallery();
setupTableHighlighting();
setupAccordion();