HTMLCollection and NodeList in JavaScript Document Object Model (DOM): A Comprehensive Guide
· Introduction
· What is HTMLCollection?
· What is a NodeList?
· Similarities between HTMLCollection and NodeList
∘ Array-like Behaviour
∘ Length Property
· Differences between HTMLCollection and NodeList
∘ 1. Content
∘ 2. Live Collections vs. Static Collections
∘ 3. Accessing Elements
∘ 4. Obtaining
· Choosing the Right Tool
∘ HTMLCollection
∘ NodeList
· Conclusion
Introduction
Have you ever navigated the complex world of JavaScript’s Document Object Model (DOM) and come across the terms HTMLCollection
and NodeList
? These objects are similar, but they serve different purposes when working with web page elements. These objects show different characteristics and behaviours that every web developer should know.
In this article, you will embark on a journey to learn, and understand HTMLCollection
and NodeList
. Starting from their origins to their significance in modern web development, you will learn their similarities, differences, and real-world applications of these objects. Following this article to the end, you will be able to confidently navigate the fascinating world of DOM manipulation.
What is HTMLCollection?
HTMLCollection
is an interface in the DOM that represents a collection of HTML document elements. It is commonly used when you want to access a group of elements with a specific tag name or class name, such as all <div>
elements or all <p>
elements, or when you want to access elements within a specific container, such as all elements within a <ul>
element.
HTMLCollection
is live, meaning that it is automatically updated when the underlying document is modified. This means that if elements are added, removed, or modified in the document, the HTMLCollection
object will reflect those changes immediately. HTMLCollection
can be accessed via methods such as getElementByTagName()
, and getElementByClassName()
.
An example of the JavaScript DOM method using the getElementByTagName()
.
Code example:
<p class="para">First Paragraph</p>
<p class="para">Second Paragraph</p>
<p class="para">Third Paragraph</p>
In the code example above, we have three HTML <p>
tags each with the class name para
. Now, let's select them using the JavaScript getElementByClassName()
method.
let paraEl = document.getElementsByTagName('p');
console.log(paraEl);
The JavaScript code above retrieves all the HTML <p>
elements in the document using getElementsByTagName()
and stores them in a variable namedparaEl
. The getElementsByClassName()
method returns an HTMLCollection
and then the result is printed to the console using console.log
. A screenshot of the result is below.
What is a NodeList?
A NodeList
is another interface in the DOM that represents a collection of document nodes (element nodes, attribute nodes, text nodes, comments, essentially any type of node in the DOM tree), typically used in the context of web development with JavaScript.
A NodeList
is most often a static collection. NodeList
objects are commonly returned by methods like querySelectorAll()
and properties like childNodes()
and children when accessing elements in the DOM. They can be iterated over using methods like forEach()
or by accessing them by index, like an array.
An example of the JavaScript DOM method using the querySelectorAll()
.
Code example:
<p class="para">First Paragraph</p>
<p class="para">Second Paragraph</p>
<p class="para">Third Paragraph</p>
In the code example above, we have three HTML <p>
tags each with the class name para
. Now, let's select them using the JavaScript querySelectorAll()
method instead.
let paraEl = document.querySelectorAll('p');
console.log(paraEl);
The JavaScript code above retrieves all the HTML <p>
elements in the document using querySelectorAll()
and stores them in a variable named paraEl
. The querySelectorAll()
method returns a NodeList
and then the result is printed to the console using console.log
. A screenshot of the result is below.
Similarities between HTMLCollection and NodeList
HTMLCollection
and NodeList
have several key similarities, including:
Array-like Behaviour
HTMLCollection
and NodeList
both resemble arrays. Even though they are not true arrays, they resemble arrays in their structure. You can access elements within them using zero-based indexing (starting from index 0). This means you can use the index to retrieve a specific element, like sample[0]
for the first element in the array.
Length Property
HTMLCollection
and NodeList
both have the length property, which indicates the total number of elements contained in the collection. This allows you to iterate through the collection using loops or other array-like methods.
Example:
<p class="para">First Paragraph</p>
<p class="para">Second Paragraph</p>
<p class="para">Third Paragraph</p>
This is a <p>
tag with three paragraphs. Let’s see examples of accessing the elements with zero-based indexing and also checking the length for both HTMLCollection
and NodeList
.
In the code example above, we have three HTML <p>
tags each with the class name para
. Let’s see examples of accessing the elements with zero-based indexing and also checking the length for both HTMLCollection
and NodeList
.
Example of array-like behaviour and length property with HTMLCollection
:
// The getElementsByTagName() method will return an HTMLCollection
const paraEl = document.getElementsByTagName('p');
console.log(paraEl);
// Use the index to get the last paragraph
let lastPara = paraEl[2];
console.log(lastPara);
// Use the length property
console.log(paraEl.length);
The JavaScript code above retrieves all <p>
elements in the document using getElementsByTagName('p')
and stores them in an HTMLCollection
named paraEl
. It then logs the HTMLCollection
to the console. Next, it retrieves the third <p>
element from the HTMLCollection
using paraEl[2]
and stores it in lastPara
, then logs lastPara
to the console.
Lastly, it logs the number of <p>
elements in the HTMLCollection
to the console using the length property in paraEl.length
. A screenshot of the result is below.
Example of array-like behaviour and length property with NodeList
:
// The querySelectorAll() method will return a Nodelist
let paraEl = document.querySelectorAll('p');
console.log(paraEl);
// Use the index to get the last paragraph
let lastPara = paraEl[2];
console.log(lastPara);
// Use the length property
console.log(paraEl.length);
The JavaScript code in the example above uses the querySelectorAll()
method to select all the <p>
elements in the document and stores them in a NodeList
named paraEl
. It then logs the NodeList
to the console. Next, it retrieves the third <p>
element from the NodeList
using paraEl[2]
and stores it in lastPara
, then logs lastPara
to the console.
Lastly, it logs the number of <p>
elements in the NodeList
to the console using the length property in paraEl.length
. A screenshot of the result is below.
Differences between HTMLCollection and NodeList
HTMLCollection
and NodeList
have some key differences, which include the following:
1. Content
HTMLCollection
is primarily focused on element nodes (e.g., <p>
, <div>
, <img>
), and other elements nested within the HTML structure. NodeList
covers a wider range of nodes, including element nodes (e.g., <p>
, <div>
, <img>
), text nodes (actual text content within elements), and attribute nodes (attributes associated with elements, like href
in an <a>
tag).
Code example:
<div id="parent">
<p>This is a paragraph</p>
<span>This is a span</span>
This is a text node
</div>
The code example above is a <div>
element with an id parent
that contains a <p>
element, a <span>
element, and a text node (a piece of text not enclosed in an element). Both the <p>
and <span>
elements have text nodes inside them.
// Find the first <div> element in the HTML document
const divElement = document.querySelector('div');
// Print a message indicating that we're using the children method to get the child elements
console.log("HTML Collection using the children method:");
// Print the list of child elements (HTMLCollection) of the <div> element
console.log(divElement.children);
// Print a message indicating that we're going to print the text content of each child element
console.log("Content:");
// Loop through each child element and print its text content
for (let i = 0; i < divElement.children.length; i++) {
console.log(divElement.children[i].textContent);
}
// Print a message indicating that we're using the childNodes method to get all child nodes
console.log("Node List using the ChildNodes method:");
// Print the list of all child nodes (NodeList) of the <div> element
console.log(divElement.childNodes);
// Print a message indicating that we're going to print the text content of each child node
console.log("Content:");
// Loop through each child node and print its text content
for (let i = 0; i < divElement.childNodes.length; i++) {
console.log(divElement.childNodes[i].textContent);
}
The code example above retrieves a <div>
element from the HTML document using document.querySelector()
method. It then demonstrates the difference between children
and childNodes
properties of the element. Now, let me break it down in the following steps:
divElement.children
: This property returns anHTMLCollection
containing only the element's child elements (i.e., the<p>
and<span>
elements excluding text nodes and comment nodes inside them). The code logs each child element's text content using afor
loop.divElement.childNodes
: This property returns aNodeList
containing all the child nodes (i.e., the<p>
and<span>
elements including text nodes and comment nodes inside them). The code also logs the text content of each node using afor
loop.- The code uses
console.log
statements to print the contents of both collections. A screenshot of the result is below.
From the screenshot image of the code example above, you’ll see that the HTMLCollection
obtained using the children
property only includes the direct child elements of the <div>
(i.e., the <p>
and <span>
elements), excluding any hidden text or comments. This is why it shows two items.
On the other hand, the NodeList
obtained using the childNodes
property includes all types of child nodes, such as elements, text nodes, and comments, that are direct children of the <div>
. This is why it shows five items (i.e., the <p>
and <span>
elements, text nodes, and comments).
If you only want to get the element nodes inside a <div>
, you can use the children
property which returns an HTMLCollection
containing only element nodes.
However, if you want all nodes, not just the element nodes that return a NodeList
, you can get them all using the childNodes
property.
2. Live Collections vs. Static Collections
The terms “live” and “static” in the context of HTMLCollection
and NodeList
describe how these collections behave when changes are made to the DOM. Here’s a breakdown:
An HTMLCollection
is Always Live
In the live collection, the changes made to the underlying HTML document, such as adding, removing, or modifying elements, are automatically updated in the HTMLCollection
.
Code example:
<div class="items">Item 1</div>
<div class="items">Item 2</div>
<div class="items">Item 3</div>
The code example above creates three <div>
elements, each with the class "items" and containing text that indicates an item.
// Get all elements with the class "items" which returns an HTMLCollection
const items = document.getElementsByClassName('items');
// Log the initial length of the HTMLCollection
console.log('HTMLCOLLECTION INITIAL LENGTH BEFORE UPDATE: ', items.length); //Output: 3
//Returns an HTML Collection
console.log('HTMLCOLLECTION BEFORE UPDATE: ', items);
//Add a new div with a class of "items"
const newDiv = document.createElement('div');
newDiv.className = 'items'; // Set the class name for the new div
// Append the new div to the document body or another parent element
document.body.appendChild(newDiv);
// Log the final length of the HTMLCollection after the update
console.log('HTMLCOLLECTION FINAL LENGTH AFTER UPDATE: ', items.length); //Output: 4 (HTMLCollection is live and not affected by direct DOM manipulation)
console.log('HTMLCOLLECTION AFTER UPDATE: ', items);
The code example above retrieves all elements with the class “items” and stores them in an HTMLCollection
called items
. It then logs the initial length of the items
collection. Next, it creates a new <div>
element with the class "items" and appends it to the document body.
Finally, it logs the final length of the items
collection, demonstrating that the HTMLCollection
is live and reflects changes to the DOM. A screenshot of the result is below.
From the screenshot image of the code example above, you’ll see the HTMLCollection
had three <div>
elements before the update. But after the update, the HTMLCollection
now has four <div>
elements, reflecting the change in the document.
A NodeList
is often Static
In the static collection, the changes made to the underlying HTML document, such as adding, removing, or modifying elements, are not automatically updated in the NodeList
.
Code example:
<div class="items">Item 1</div>
<div class="items">Item 2</div>
<div class="items">Item 3</div>
The code example above creates three <div>
elements, each with the class "items" and containing text that indicates an item.
// Get all elements with the class "items" which returns a NodeList
const divs = document.querySelectorAll('div');
// Log the initial length of the NodeList
console.log('NODELIST INITIAL LENGTH BEFORE UPDATE: ', divs.length); //Output: 3
//Returns a NodeList
console.log('NODELIST BEFORE UPDATE: ', divs);
//Add a new div with a class of "items"
const newDiv = document.createElement('div');
newDiv.className = 'items'; // Set the class name for the new div
// Append the new div to the document body or another parent element
document.body.appendChild(newDiv);
// Log the final length of the NodeList after the update
console.log('NODELIST FINAL LENGTH AFTER UPDATE: ', divs.length); //Output: 3 (NodeList is static and not automatically updated when the DOM is manipulated directly)
console.log('NODELIST AFTER UPDATE: ', divs);
The code example above retrieves all <div>
elements in the document using document.querySelectorAll('div')
and stores them in a NodeList
called divs
. It then logs the initial length of the NodeList
. Next, it creates a new <div>
element with the class "items" and appends it to the document body.
Finally, it logs the final length of the NodeList
, showing that the NodeList
is static and does not automatically update to reflect the new element added to the DOM. It’s important to note that the NodeList
(divs
) does not automatically update when the DOM is manipulated directly, so the final length of the NodeList
will remain the same as the initial length. A screenshot of the result is below.
From the screenshot image of the code example above, you’ll see that the NodeList
had three<div>
elements before the update. But after the update, the NodeList
still has three <div>
elements, reflecting no change in the document.
Note: In the live collection, the changes made to the underlying HTML document, such as adding, removing, or modifying elements, are automatically updated in the NodeList
re-querying the DOM.
To get the updated length of the NodeList
after adding a new element for instance, you need to re-query the DOM using document.querySelectorAll('div')
or a similar method. Since NodeList
is static and does not update automatically, re-querying the DOM will give you a new NodeList
that includes the newly added element.
Code example:
<div class="items">Item 1</div>
<div class="items">Item 2</div>
<div class="items">Item 3</div>
The code example above creates three <div>
elements, each with the class "items" and containing text that indicates an item.
// Get all elements with the class "items" which returns a NodeList
let divs = document.querySelectorAll('div');
// Log the initial length of the NodeList
console.log('NODELIST INITIAL LENGTH BEFORE UPDATE: ', divs.length); //Output: 3
//Returns a NodeList
console.log('NODELIST BEFORE UPDATE: ', divs);
//Add a new div with a class of "items"
const newDiv = document.createElement('div');
newDiv.className = 'items'; // Set the class name for the new div
// Append the new div to the document body or another parent element
document.body.appendChild(newDiv);
// Re-query the DOM to get the updated NodeList
divs = document.querySelectorAll('div');
// Log the final length of the NodeList after the update
console.log('NODELIST FINAL LENGTH AFTER UPDATE AND RE-QUERYING: ', divs.length); //Output: 4
console.log('NODELIST AFTER UPDATE AND RE-QUERYING: ', divs);
In this code, we first obtain a NodeList
of all <div>
elements in the document and log its initial length. We then add a new <div>
element to the document, append it to the body, and re-query the document to get the updated NodeList
. Finally, we log the updated length of the NodeList
and the NodeList
itself before and after the update.
This approach demonstrates how to effectively work with NodeList
and re-query the DOM to reflect changes made to the document. A screenshot of the result is below.
From the screenshot image of the code example above, you’ll see that the NodeList
had three<div>
elements before the update. But after re-querying the DOM, the NodeList
now have four <div>
elements, reflecting the change in the document.
3. Accessing Elements
An HTMLCollection
is accessed by index number (starting from 0) and additionally allows accessing elements by their ID or name if they are unique, while a NodeList
is also accessed by index number (starting from 0) but does not allow accessing elements by ID or name.
4. Obtaining
An HTMLCollection
is typically obtained using methods like getElementsByTagName(tagName)
or getElementsByClassName(className)
to select elements by tag name or class name.
A NodeList
is typically obtained using querySelectorAll(selector)
to select elements or by accessing the childNodes()
property of an element, which returns all child nodes, including text and attribute nodes.
Choosing the Right Tool
HTMLCollection
Use HTMLCollection
when you need to manipulate specific groups of HTML elements and want a collection that reflects dynamic changes to the DOM.
NodeList
Use NodeList
when you need to access a broader representation of the DOM structure at a specific point in time, including text and attribute nodes, and it doesn’t require live updates.
Conclusion
While both collections are array-like and used for DOM manipulation, understanding their differences in content, live vs. static behaviour, accessing methods, and obtaining mechanisms are crucial for selecting the appropriate tool for your specific needs.
However, it is important to understand their differences in terms of content, live versus static behaviour, access methods, and retrieval mechanisms to choose the most suitable tool for your particular requirements.
If you find this article helpful, please consider clapping, sharing, and following me for more front-end development tips and tricks! Thank you for your support! 🙌