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

5
  • check out the sizzle.js javascript selector library Commented Feb 29, 2012 at 9:28
  • 1
    Nice yea the only selecting I need to do is data attributes so I was trying to figure the simplest way to patch that without pulling in a whole selector engine like Sizzle. But good point to look in the source. BTW another great selector engine is github.com/ded/qwery Commented Feb 29, 2012 at 9:45
  • The working solution that I used is in github.com/ryanve/dope/blob/master/dope.js in the method called 'queryAttr' Commented Nov 24, 2012 at 19:39
  • 7
    Lol, your question is my answer. So this come with another question. In what situation that querySelectorAll is not available? note - I don't care all IE Commented Jul 31, 2013 at 14:14
  • @vzhen See QSA availability here. Note QSA is limited to the CSS selectors supported by the browser. Compare CSS2 support to CSS3 support. IE8 supports CSS2 but not CSS3 selectors. Commented Jul 31, 2013 at 17:22

8 Answers 8

142

You could write a function that runs getElementsByTagName('*'), and returns only those elements with a "data-foo" attribute:

function getAllElementsWithAttribute(attribute)
{
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++)
  {
    if (allElements[i].getAttribute(attribute) !== null)
    {
      // Element exists with attribute. Add to array.
      matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

Then,

getAllElementsWithAttribute('data-foo');
Sign up to request clarification or add additional context in comments.

3 Comments

Using != null is the ideal way (better than my comment above) because in old IE it is possible for getAttribute to return a value whose typeof is 'number'
Why using document.getElementsByTagName('*') instead of document.all?
Why not use hasAttribute rather than getAttribute() !== null, since you only want to check for existence and not its value?
67

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

3 Comments

How does this have so many upvotes when the question explicitly requests: "I need a native solution that works at least in IE7". Secondly, that link states that support starts in IE11 even though it actually starts from IE8 - maybe this should be swapped to developer.mozilla.org/en-US/docs/Web/API/Element/… so it actually supports the answer...?
The reason for all the upvotes, and the reason I made the answer, is that this SO question is really old, so when you search for how to find DOM elements you find this question very high in the search results, and since it's what people are looking for they upvote. Usefulness > historical accuracy. Secondly the link still works just fine, it's just that caniuse.com has hidden old browsers, if you switch to "Usage relative" you'll still see the old browsers.
Worked perfectly. Quick and simple
45

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]');

1 Comment

Aye, +1 for querySelectorAll. A quick jsperf test jsperf.com/custom-vs-selectorall-attributes shows that it's much faster than the accepted answer... unfortunately it's not IE 7 compatible :(
19

Try this it works

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

example :

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

Comments

5

That works too:

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

So:

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

1 Comment

This is missing the single quotes in the actual querySelector. Should be: document.querySelector('[data-foo="bar"]');
1

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

Comments

0

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');

1 Comment

What did you change and why?
-1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.