This guide covers the querySelector() and querySelectorAll() methods – how they work, when to use each one, and how to loop through the results.
The DOM (Document Object Model) represents all HTML elements in a tree structure. Each element in that tree can be accessed using JavaScript and the browser’s built-in API. The querySelector and querySelectorAll methods are the most flexible way to select elements from the DOM because they accept any valid CSS selector.
Take a look at the following markup. We will use it for all the examples in this post:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>JavaScript DOM API querySelector and querySelectorAll Examples</title>
</head>
<body>
<div class="wrapper">
<div class="name">Liam</div>
<div class="name">Noah</div>
<div class="name">William</div>
<div class="name">James</div>
<div class="name">Benjamin</div>
<div class="name">Elijah</div>
</div>
<div id="country">USA</div>
<footer>Just some footer text</footer>
<script>
// code goes here
</script>
</body>
</html>querySelectorAll – Example
The syntax for querySelectorAll:
const elements = parentNode.querySelectorAll(cssSelector);To find all div elements with the class name in the HTML structure above:
<script>
const names = document.querySelectorAll(".name");
console.log(names);
</script>Line 2 returns a NodeList containing all six elements with the class name.

querySelector – Example
While querySelectorAll returns all matching elements, querySelector returns only the first match. Here is the syntax:
const element = parentNode.querySelector(cssSelector);The querySelector method accepts any CSS selector as an argument and returns the first matching element, or null if no match is found.
<script>
const country = document.querySelector("#country");
console.log(country);
</script>This returns the element with the ID country.

querySelector vs. getElementById and getElementsByClassName
You may wonder when to use querySelector over older methods like getElementById() and getElementsByClassName(). The key difference is that querySelector and querySelectorAll accept any CSS selector, making them far more flexible. You can use complex selectors like div.wrapper > .name:first-child or [data-role="close"].
However, getElementById() is faster because it uses the browser’s internal ID lookup table directly. In benchmarks, it runs roughly 2x faster than querySelector(). For simple ID lookups in performance-critical code, getElementById() is the better choice.
There is one important difference between the results these methods return. querySelectorAll() returns a static NodeList – a snapshot of the DOM at the time of the query. Methods like getElementsByClassName() return a live HTMLCollection that updates automatically when the DOM changes. Keep this in mind when your code modifies the DOM while iterating over the results.
Looping through a NodeList with forEach
The querySelectorAll method returns a NodeList, which supports the forEach() method in all modern browsers (Chrome 51+, Firefox 50+, Safari 10+, Edge 16+):
const names = document.querySelectorAll(".name");
names.forEach((element) => {
console.log(element);
});
You can also use a for...of loop, which works the same way and has equally broad support:
const names = document.querySelectorAll(".name");
for (const element of names) {
element.style.color = "blue";
}
If you need array methods like
map(),filter(), orreduce()on the results, spread the NodeList into an array first:[...document.querySelectorAll(".name")].
Scoping querySelector to a Parent Element
Both querySelector and querySelectorAll can be called on any element, not just document. This scopes the search to that element’s descendants, which is useful for working with components or sections of a page:
const wrapper = document.querySelector(".wrapper");
const firstChild = wrapper.querySelector(".name");
console.log(firstChild.textContent); // "Liam"FAQs
Common questions about querySelector and querySelectorAll:
querySelector() returns the first element that matches a CSS selector, or null if no match is found. querySelectorAll() returns a static NodeList of all matching elements, or an empty NodeList if there are no matches. Use querySelector() when you need one element and querySelectorAll() when you need all of them.getElementById() is roughly 2x faster because browsers maintain an internal ID lookup table that allows direct access. querySelector() uses a CSS selector engine, which adds parsing overhead. In practice, the difference is negligible for most applications, but for performance-critical loops, getElementById() is the better choice for simple ID lookups.querySelectorAll() returns a static NodeList - a snapshot of the DOM at the time of the call. If the DOM changes afterward, the NodeList does not update. This is different from getElementsByClassName() and getElementsByTagName(), which return live HTMLCollections that reflect DOM changes automatically.querySelector() and querySelectorAll() are available on any DOM element, not just document. Calling them on a specific element scopes the search to that element's descendants. For example, wrapper.querySelector(".item") only searches inside the wrapper element.querySelector() returns null when no element matches the selector. querySelectorAll() returns an empty NodeList (with a length of 0). Always check the result of querySelector() for null before accessing properties on it, or you will get a TypeError.Summary
querySelector() returns the first matching element, while querySelectorAll() returns a static NodeList of all matches. Both accept any CSS selector, making them more flexible than getElementById() or getElementsByClassName(), though the older methods are faster for simple lookups. You can loop through a NodeList using forEach() or for...of in all modern browsers, and scope your queries to a specific parent element to narrow the search.
Here are related posts on the topic:

