Loop Over querySelectorAll Matches

Let's look at some options for iterating over a NodeList, as you get back from running a document.querySelectorAll.

We've written an updated article about this: A Bunch of Options for Looping Over querySelectorAll NodeLists.

Not all browsers support forEach on NodeLists, but for those that do:

buttons.forEach((button) => {
  button.addEventListener('click', () => {
    console.log("forEach worked");

Here's a tricky way to get around that with a bit deeper browser support.

var divs = document.querySelectorAll('div');

[].forEach.call(divs, function(div) {
  // do whatever
  div.style.color = "red";

Fair warning, Todd Motto explains why this method is a rather hacky, detailing over 10 problems with it.

You could also use a classic for loop:

var divs = document.querySelectorAll('div'), i;

for (i = 0; i < divs.length; ++i) {
  divs[i].style.color = "green";

Todd's suggestion is to make your own method:

// forEach method, could be shipped as part of an Object Literal/Module
var forEach = function (array, callback, scope) {
  for (var i = 0; i < array.length; i++) {
    callback.call(scope, i, array[i]); // passes back stuff we need

// Usage:
// optionally change the scope as final parameter too, like ECMA5
var myNodeList = document.querySelectorAll('li');
forEach(myNodeList, function (index, value) {
  console.log(index, value); // passes index + value back!

You can also spread the list yourself, which then would give you access to other array methods while you're at it.

[...buttons].forEach((button) => {
  button.addEventListener('click', () => {
    console.log("spread forEach worked");

There are also for..of loops. Firefox was the first to support this but support has gotten pretty good:

for (const button of buttons) {
  button.addEventListener('click', () => {
    console.log("for .. of worked");

This is pretty intense (probably dangerous and not recommended) but you could make NodeList have the same forEach function as Array does, then use it.

NodeList.prototype.forEach = Array.prototype.forEach;

var divs = document.querySelectorAll('div').forEach(function(el) {
  el.style.color = "orange";

There is a bit more information in the MDN article.


  1. User Avatar
    Permalink to comment#

    The safer way to do the last version and co-opt the Array method would be to do something like this:

    Array.prototype.forEach.call(document.querySelectorAll('div'), function(div) { console.log(div); })

    Of course, you still need to make sure you have a polyfill for Array.forEach if you’re targeting older browsers.

  2. User Avatar
    Permalink to comment#

    Hey this saved me some time – I was curious why I couldn’t loop over with forEach. Thanks!

  3. User Avatar
    Permalink to comment#

    there is a pretty nice function that gives you a array:

    function getDomNodeArray(selector) {
    // get the elements as a DOM collection
    var elemCollection = document.querySelectorAll(selector);

    // coerce the DOM collection into an array
    var elemArray = Array.prototype.slice.apply(elemCollection);

    return elemArray;

    • User Avatar
      Mauro Cn
      Permalink to comment#

      That’s exactly what I use. I use an extra optional argument, which is the “context” or the element in which the querySelectorAll() is called (default is document)

      function $$(query, context) {
        return Array.prototype.slice.call(
          (context || document).querySelectorAll(query)

      Then usage may be:

      $$('p').forEach(function() {});
      var myForm = document.querySelector('#myForm');
      // the following can be read as: "all input type checkbox INSIDE myForm"
      var checkedBoxes = $$('input[type="checkbox"]', myForm).filter(function(inp) { return this.checked});

      ETC…. It is very powerful yet very simple. It has also a one-line-form:

      function $$(q, c) {return Array.prototype.slice.call((c||document).querySelectorAll(q));}

      I just wanted to share this “discovery”….

  4. User Avatar
    Permalink to comment#

    ES2015 variant using spread operator:

  5. User Avatar
    Permalink to comment#

    If you’re using ES6, you should also be able to do this:

    Array.from(querySelectorAll('img')).forEach(img => doStuff);

    Clean and simple.

  6. User Avatar
    Burak Kalkan
    Permalink to comment#

    Overload the NodeList, then no headache :)

    NodeList.prototype.forEach = Array.prototype.forEach;
      // code
  7. User Avatar
    Gabriel Santerre
    Permalink to comment#

    This is should be the fastest way:

    var arr = [];
    for (var i = 0, ref = arr.length = nl.length; i < ref; arr[i] = nl[i++]);
    • User Avatar
      Gabriel Santerre
      Permalink to comment#

      nl equal to a NodeLIst

    • User Avatar
      Mauro Cn
      Permalink to comment#

      A different aproach, a little more straightforward:

      // nl = document.querySelectorAll('blabla');
      for(var arr=[], i=nl.length;i;arr[--i]=nl[i]);


  8. User Avatar
    Permalink to comment#

    You can also do

    function toArray(arr) { var a = []; a.push.apply(a, arr); return a; }
    var elements = toArray(document.querySelectorAll('div'));
  9. User Avatar
    Permalink to comment#

    or you could just use Array.from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from

    then it would actually be an Array.

    var arr = Array.from(document.querySelectorAll('div'));
  10. User Avatar
    Mark D
    Permalink to comment#
    [].map.call(myArrayVar, function(myVar){
        // do something here with 'myVar'
  11. User Avatar
    Permalink to comment#

    What about this:

  12. User Avatar
    Permalink to comment#

    I just noticed that NodeList.prototype.forEach() ist obviously now party of the official JS-API in Chrome & Firefox. See https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach for details and the official polyfill.

Leave a Comment

Posting Code!

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.