Loop Over querySelectorAll Matches

You can loop over Arrays easily in JavaScript with forEach, but unfortunately, it's not that simple with the results of a querySelectorAll.

/* Not Reliable */
document.querySelectorAll('.module').forEach(function() {
  /* Only works in Blink browsers and Firefox 50+
     no Safari or IE/Edge support */
});

That's because what you get back from querySelectorAll isn't an array, it's a (non-live) NodeList, and not all browsers support forEach on NodeList's

Here's a quick way to iterate over all the found elements:

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!
});

There are also for..of loops, but...

/* Be warned, this only works in Firefox */

var divs = document.querySelectorAll('div );

for (var div of divs) {
  div.style.color = "blue";
}

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.

Comments

  1. User Avatar
    Aneece
    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
    b
    Permalink to comment#

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

  3. User Avatar
    wumble
    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
    topek
    Permalink to comment#

    ES2015 variant using spread operator:

    [...document.querySelectorAll('img')].forEach(doStuff);
    
  5. User Avatar
    Todd
    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;
    
    document.querySelectorAll('img').forEach(function{
      // 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]);
      

      (Tested.)

  8. User Avatar
    Corey
    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'));
    
    elements.forEach(...)
    
  9. User Avatar
    dave
    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
    Peter
    Permalink to comment#

    What about this:

    [].concat(document.querySelectorAll('img')].forEach(doStuff);
    
  12. User Avatar
    fboes
    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.

Submit 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.

icon-anchoricon-closeicon-emailicon-linkicon-logo-staricon-menuicon-nav-guideicon-searchicon-staricon-tag