JS getElementsByClassName vs querySelector Guide

Compare getElementsByClassName and querySelector to understand live vs static collections, performance, and when each DOM selection method is the right choice.

4 min read

Both getElementsByClassName and querySelector can find elements by their CSS class. The difference is not in what they find, it is in what they return and how that return value behaves over time.

One gives you a live, self-updating collection. The other gives you a static snapshot.

Here is the core distinction in one comparison:

getElementsByClassNamequerySelector / querySelectorAll
ReturnsLive HTMLCollectionStatic element or NodeList
Updates with DOM?Yes, automaticallyNo, snapshot at call time
Selector typeClass name onlyAny CSS selector
IterationConvert to array firstforEach built in (NodeList)
SpeedFaster for class lookupParses CSS selector

A live collection stays connected to the page. Add a new element with the matching class and it appears in the collection without re-querying.

A static result is a one-time snapshot. Add a new element later and your existing variable will not include it.

Live Collection: getElementsByClassName

The defining feature of getElementsByClassName is that it returns a live HTMLCollection. Every time the DOM changes, the collection updates to match the current state of the page.

javascriptjavascript
const cards = document.getElementsByClassName("card");
console.log(cards.length);  // Suppose it is 3
 
const newCard = document.createElement("div");
newCard.className = "card";
document.body.appendChild(newCard);
 
console.log(cards.length);  // Now 4 -- automatically updated

No second call to getElementsByClassName is needed. The cards variable watched the DOM change and updated itself. This is useful when you are adding and removing elements in the same script and want a single reference that always reflects the current state.

HTMLCollections have one limitation: they do not support forEach directly. Convert to an array before iterating:

javascriptjavascript
const items = document.getElementsByClassName("item");
Array.from(items).forEach((item) => {
  item.style.border = "1px solid blue";
});

Array.from or spread syntax both create a real array from the HTMLCollection, giving you access to all array methods.

Static Snapshot: querySelector and querySelectorAll

The querySelector family returns static results. The element or NodeList you get back is a snapshot of what existed at the moment you made the call.

javascriptjavascript
const cards = document.querySelectorAll(".card");
console.log(cards.length);  // Suppose it is 3
 
const newCard = document.createElement("div");
newCard.className = "card";
document.body.appendChild(newCard);
 
console.log(cards.length);  // Still 3 -- the snapshot did not update

The new card element is on the page, visible to the user, but the cards NodeList does not know about it. If you need the updated list, you must call querySelectorAll again.

This static behavior is usually what you want. It means your loop will not suddenly grow while you are iterating, and the results are predictable no matter what other code does to the page afterward.

The Flexibility Advantage

querySelector accepts any CSS selector, not just a class name. This makes it far more flexible when you need more than a simple class match:

javascriptjavascript
// Only active cards
document.querySelectorAll(".card.active");
 
// Cards inside a specific section
document.querySelectorAll("#featured .card");
 
// Cards with a data attribute
document.querySelectorAll('.card[data-type="premium"]');

getElementsByClassName can only match by class name. For anything more specific, you must use querySelector or querySelectorAll.

When to Use Each

Use getElementsByClassName when you specifically need a live collection that stays in sync with the DOM. The most common case is when you are adding or removing elements dynamically and want a single reference that always reflects the current count.

Use querySelector when you need a clean, predictable snapshot. This covers most situations: reading elements once, applying styles, attaching event listeners, and filtering by anything beyond a simple class match.

For an overview of all five DOM selection methods and how they compare, see the complete guide to selecting DOM elements. If you are new to DOM selection entirely, start with what the DOM is.

Rune AI

Rune AI

Key Insights

  • getElementsByClassName returns a live HTMLCollection that updates automatically.
  • querySelector and querySelectorAll return static results that do not change.
  • getElementsByClassName is slightly faster for class-only lookups.
  • querySelector is more flexible, accepting any CSS selector.
  • Default to querySelector unless you specifically need a live collection.
RunePowered by Rune AI

Frequently Asked Questions

Which is faster, getElementsByClassName or querySelector?

getElementsByClassName is faster because it does a targeted class lookup. querySelector must parse a CSS selector string first. In most real code the difference is negligible, but in loops or performance-sensitive code the direct method has an edge.

Can querySelector replace getElementsByClassName entirely?

Yes, in most cases. querySelector('.class') and querySelectorAll('.class') cover the same use cases. The only reason to use getElementsByClassName is when you specifically need a live HTMLCollection that updates as the DOM changes.

Why does getElementsByClassName return an HTMLCollection and not a NodeList?

It is a legacy method from the early DOM API. HTMLCollection was the standard collection type before NodeList gained widespread use. The live behavior is a feature of HTMLCollection that some developers rely on.

Conclusion

getElementsByClassName and querySelector both select elements by class, but they differ in one fundamental way: live versus static. getElementsByClassName returns a live HTMLCollection that updates with the DOM. querySelector and querySelectorAll return static snapshots. Choose the one that matches your specific need, and default to querySelector when you do not need live updates.