Skip to main content Accessibility Feedback

Static versus live NodeLists and HTMLCollections in vanilla JavaScript

NodeLists and HTMLCollections are two types of array-like collections of objects. They work similarly, with a few notable differences, and can both be looped through with a for...of loop.

Today, I want to talk about the difference between static and live collections of DOM nodes in JavaScript. Let’s dig in!

(Why there are so many different array-like collections of things in JavaScript is another article for another day.)

Sample HTML

Let’s imagine you have some HTML that looks like this.

<div id="sandwiches">
	<p class="sandwich" id="tuna">Tuna</p>
	<p class="sandwich" id="pbj">PB&J</p>
	<p class="sandwich" id="turkey">Turkey</p>
</div>

You want to get the .sandwich elements so that you can work with them.

Static Collections

The document.querySelectorAll() method returns a static collection.

The NodeList that you back never changes, even if the HTML elements inside the collection no longer reflect the selector you used when you first ran it.

// A NodeList with the three .sandwich elements
let sandwiches = document.querySelectorAll('.sandwich');

Let’s say you used the Element.classList.remove() method to remove the .sandwich method from the #pbj element.

// Remove the .sandwich class from #pbj
let pbj = document.querySelector('#pbj');
pbj.classList.remove('.sandwich');

The NodeList assigned to the sandwiches variable still contains the #pbj element, even though it no longer has the .sandwich class.

It’s a static collection, so it doesn’t change, even if the DOM does.

Here’s a demo.

Live Collections

By contrast, the Element.getElementsByTagName() method and Element.children property both return a live collection.

If you assign the returned HTMLCollection to a variable and the DOM changes afterwards, the HTMLCollection automatically updates to match the current state of the DOM.

// An HTML collection with the three .sandwich elements
let sandwiches = document.getElementsByTagName('p');

If you removed the #pbj element from the DOM with the Element.remove() method, the HTMLCollection assigned to sandwiches would only contain two elements.

// Remove the .sandwich class from #pbj
let pbj = document.querySelector('#pbj');
pbj.remove('.sandwich');

Here’s another demo.

Which type of collection is better?

It depends!

Typically, having a list that remains fixed is a good thing. But sometimes you might want a list that automatically updates to reflect the current UI.

Understanding whether your selector method returns a static or live collection can also help prevent unintended side-effects and bugs.