[javascript] Get elements by attribute when querySelectorAll is not available without using libraries?

<p data-foo="bar">

How can you do the equivalent to

document.querySelectorAll('[data-foo]')

where querySelectorAll is not available?

I need a native solution that works at least in IE7. I don’t care about IE6.

This question is related to javascript dom

The answer is


Try this it works

document.querySelector('[attribute="value"]')

example :

document.querySelector('[role="button"]')

I played a bit around and ended up with this crude solution:

function getElementsByAttribute(attribute, context) {
  var nodeList = (context || document).getElementsByTagName('*');
  var nodeArray = [];
  var iterator = 0;
  var node = null;

  while (node = nodeList[iterator++]) {
    if (node.hasAttribute(attribute)) nodeArray.push(node);
  }

  return nodeArray;
}

The usage is quite simple, and works even in IE8:

getElementsByAttribute('data-foo');
// or with parentNode
getElementsByAttribute('data-foo', document);

http://fiddle.jshell.net/9xaxf6jr/

But I recommend to use querySelector / All for this (and to support older browsers use a polyfill):

document.querySelectorAll('[data-foo]');

Use

//find first element with "someAttr" attribute
document.querySelector('[someAttr]')

or

//find all elements with "someAttr" attribute
document.querySelectorAll('[someAttr]') 

to find elements by attribute. It's now supported in all relevant browsers (even IE8): http://caniuse.com/#search=queryselector


That works too:

document.querySelector([attribute="value"]);

So:

document.querySelector([data-foo="bar"]);

Don't use in Browser

In the browser, use document.querySelect('[attribute-name]').

But if you're unit testing and your mocked dom has a flakey querySelector implementation, this will do the trick.

This is @kevinfahy's answer, just trimmed down to be a bit with ES6 fat arrow functions and by converting the HtmlCollection into an array at the cost of readability perhaps.

So it'll only work with an ES6 transpiler. Also, I'm not sure how performant it'll be with a lot of elements.

function getElementsWithAttribute(attribute) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) !== null);
}

And here's a variant that will get an attribute with a specific value

function getElementsWithAttributeValue(attribute, value) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) === value);
}

A little modification on @kevinfahy 's answer, to allow getting the attribute by value if needed:

function getElementsByAttributeValue(attribute, value){
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++) {
    if (allElements[i].getAttribute(attribute) !== null) {
      if (!value || allElements[i].getAttribute(attribute) == value)
        matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

Try this - I slightly changed the above answers:

var getAttributes = function(attribute) {
    var allElements = document.getElementsByTagName('*'),
        allElementsLen = allElements.length,
        curElement,
        i,
        results = [];

    for(i = 0; i < allElementsLen; i += 1) {
        curElement = allElements[i];

        if(curElement.getAttribute(attribute)) {
            results.push(curElement);
        }
    }

    return results;
};

Then,

getAttributes('data-foo');