Monday code giveaway: getElementsByAttribute
Updated September 27th 2006
Apparently Opera’s claim to support document.all in conjunction with not mimicking it exactly like IE led to some problems in Opera 9. Thanks to Ash Searle who tipped me about this and also explained what the problem was. The code below and the JavaScript file to download are updated.
Since we all have to face a new hard tough week now, I thought I’d brighten your day by giving you some code that might be useful.
Ever run into a situation where you want to get an array of all elements with a specific attribute? Or even want elements with a certain value for that chosen attribute, as well? That’s not a problem anymore; let me present getElementsByAttribute.
/*
Copyright Robert Nyman, http://www.robertnyman.com
Free to use if this text is included
*/
function getElementsByAttribute(oElm, strTagName, strAttributeName, strAttributeValue){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var oAttributeValue = (typeof strAttributeValue != "undefined")? new RegExp("(^|\\s)" + strAttributeValue + "(\\s|$)") : null;
var oCurrent;
var oAttribute;
for(var i=0; i<arrElements.length; i++){
oCurrent = arrElements[i];
oAttribute = oCurrent.getAttribute && oCurrent.getAttribute(strAttributeName);
if(typeof oAttribute == "string" && oAttribute.length > 0){
if(typeof strAttributeValue == "undefined" || (oAttributeValue && oAttributeValue.test(oAttribute))){
arrReturnElements.push(oCurrent);
}
}
}
return arrReturnElements;
}
The parameters are:
- oElm
- Mandatory. This is element in whose children you will look for the attribute.
- strTagName
- Mandatory. This is the name of the HTML elements you want to look in. Use wildcard (
*) if you want to look in all elements. - strAttributeName
- Mandatory. The name of the attribute you’re looking for.
- strAttributeValue
- Optional. If you want the attribute you’re looking for to have a certain value as well.
And these are a couple of examples how it can be called:
getElementsByAttribute(document.body, "*", "id");
getElementsByAttribute(document.getElementById("the-form"), "input", "type", "text");
Web browser compatibility
The code has been tested and verified to work in:
- All Firefox versions, all the way back to Firebird (remember that one?
) - IE 5.0+, PC
- IE 5.2, Mac
- Safari 1.3
- Opera 7.03
To use it, just copy and paste above code or download the getElementsByAttribute.js file.

43 Comments/Reactions
January 23rd, 2006 at 15:21
Ok, as someone knowing the basics of DOM scripting, I think this looks really sexy and I can think of many uses for it.
Thanks for sharing. It’s nicely tucked away in my bookmarks now.
January 23rd, 2006 at 15:21
Nice! This will really come in handy. I have used Jonathan Snook’s getElementsByClassName before but I think it’s time for a change. Thanks for sharing.
January 23rd, 2006 at 16:10
Very nice! This will surely come in handy at times just like the getElementsByClassName thing.
January 23rd, 2006 at 17:08
Thank you, Robert!
January 24th, 2006 at 2:07
You know I need to know more JavaScript when I read that you were giving away a function called getElementsByAttitude.
So, which elements have attitude?
January 24th, 2006 at 9:34
Jeroen,
Thanks!
Emil,
Thank you! Regarding
getElementsByClassName, I wrote an improved version, inspired by Snook’s initial one.Marco, Alexander,
Thanks!
Jules,
Ha ha!
Well, it just has to be the
strongelement, right?January 24th, 2006 at 11:16
Great! Just yesterday I needed this function. Thanks Robert.
January 24th, 2006 at 11:32
Chris,
Great, I’m glad I could help!
January 26th, 2006 at 12:40
Mozilla has this native for
Documentobjects implementing theXULDocumentinterface.January 26th, 2006 at 13:06
Anne,
Ah, interesting to hear!
January 26th, 2006 at 13:22
Nice spotting Anne!
Robert, thanks for sharing, functions like this should always have been part of the spec…
January 26th, 2006 at 13:42
Rowan,
Yes, this one and
getElementsByClassNameare good examples of things that should be native.January 29th, 2006 at 4:12
A little to much coding for my taste. What do you think about this one?
// Javascript
function getChildren(el, a, v) {
var ar = new Array();
var ac = document.getElementById(el).getElementsByTagName(‘*’);
for (c=0; c<ac.length; c++) if (v? (ac[c][a] == v) : (ac[c][a])) ar.push(ac[c]);
return ar;
}
// Usage
getChildren(elementId, attribute, value);
// Sample
var col1 = getChildren(‘my_element’, ‘className’, ‘menuitem’);
var col2 = getChildren(‘my_element’, ‘nodeName’, ‘IMG’);
var col3 = getChildren(‘my_element’, ‘onclick’);
The third parameter (value) is optional…if undefined the function will return any element with specified attributename, regardless value.
/hbi
January 29th, 2006 at 9:36
Hakan,
Very short and concise, which I like! However, there are a few problems with it.
getElementsByTagName(’*')only works on thedocumentelement in IE 5, and not on any other element; hence the usage ofdocument.all.Just checking for
v?will return false in that if clause if you would indeed want to look for an attribute with the value0.Referring to directly to an attribute’s name through an array (
(ac[c][a] == v)) didn’t seem to work in Safari, and it threw an unexplainable error in IE on some elements. Another problem with this value comparison is that it’s case-sensitive, while some web browser are notorious for changing the case when the elements and attributes are created in their DOM.Finally, the reason for checking the length of the attribute value is because IE automatically creates a lot of attributes for every element in the DOM at runtime, so I want to make sure that is an attribute created intentionally by the programmer.
February 3rd, 2006 at 23:30
I am trying to use your code and keep getting errors that an object is required. Front Page even tells me that the HTML is no good. At this point, I suppose that is possible. Here is the button code I am trying to use to get it to run. What I am trying to do is find a div id tag that equals a certain value and then pass it to another function that I kinow works. I am trying to provide buttons on a page to copy specific code. The code I use works when I only have one code copying area per page. If I have two, then it will not work. So I figured that fi I could use code to find a specific one and then copy only that one, it might work. In any event, here is the button code that I use:
Eval –>
Thanks,
Gene
February 4th, 2006 at 21:25
EuGene,
I think you didn’t escape the HTML code properly when you posted your comment (< for < etc) . To get a reference to an element with a certain
id, just usedocument.getElementById("element-id")(remember thatids are supposed to be unique, meaning that only one instance of a certainidis correct).If that doesn't solve your problems, I think there might be two otherreasons why it doesn't work.
1) The first parameter has to be an object reference to the container where you want to look for your objects. Make sure it's valid.
2) You will not get back an object but an array reference from the function. I.e., if you think you will only get back one object, you need to reference it like this:
var oObject = getElementsByAttribute(document.body, "*", "id")[0];Good luck!
March 1st, 2006 at 8:35
Hi, it’s a nice snippet.
However, you might consider alternative for the
push()which is not supported by IE 5.0/Win.March 1st, 2006 at 8:44
Marko,
That’s the reason why there’s also an implementation for the
pushmethod for theArrayobject in the downloadable JavaScript file.However, maybe I should’ve pointed this out in the post as well…
March 17th, 2006 at 15:40
Great implementation of a general method!
And now for my wish: Could it be possibel to add a NAMESPACE parametre? You know if I add my own namespace – say “CSL” and have an attribute set on an INPUT tag: <INPUT type=”TEXT” CSL:KeepForHours=”1″>
Your method wil not be able to find elements based on attributename “CSL:KeepForHours” will it?
Why would I use namespace?
- I am working on an easy way to add cookie support for any tag through simpel HTML mark-up and a Javascript Library.
The Attribute I am considering to put in it’s own namespace. An example way to ensure that a value will live across sessions would be like the input tag named above. In that example the value of the input tag would live for 1 hour by using cookies
Cheers!
/Sten
Denmark
March 20th, 2006 at 13:19
Sten,
Thank you!
What you can do is just tweak the function to use the getAttributeNS method.
March 23rd, 2006 at 14:53
[...]getElementsByAttribute[...]
May 4th, 2006 at 11:44
[...] bsp; Firefox 1.0+, Mozilla ?, Opera ? * getElementsByAttribute * getElementsByAttribute (parent, tag name, attribute name, attribute [...]
May 18th, 2006 at 13:07
third time I’ve come back for this after losing it – about time I said thanks.
thanks.
June 20th, 2006 at 11:26
Hi,
I haven’t done extensive testing on this, but I seem to have stumbled across a problem with custom attributes.
I have following element:
<input type="button" foo="bar" value="initValue"/>
If I call your function as follows:
var buttons = getElementsByAttribute(document.body, 'input', 'foo', 'bar');
I get null result in Firefox 1.5.0.4 (it’s ok on IE6).
By changing your line:
oAttribute = oCurrent.getAttribute(strAttributeName);
to instead use eval() to do direct property access:
oAttribute = eval('oCurrent.'+strAttributeName);
it seems to work ok on both Firefox and IE6. I’m assuming there is no intentional restriction in getAttribute function with regards to custom attributes, and that this is just a bug in Firefox Element::getAttribute.
Thanks for your function!
June 20th, 2006 at 14:34
Jim,
I didn’t know that. My guess is that it is probably intentional by Firefox since they want to be as valid and correct as possible, and custom attributes shouldn’t be in the HTML code (this is a big discussion for another day…
) and aren’t allowed if you want to have a web page with valid code (unless you use a custom DTD and so on).
Anyway, with that said, if you have that specific need for custom attributes I’m happy to hear that your workaround seems to work out fine for you. However, I will let this function hold on to the W3C recommended way of accessing attributes in the DOM.
September 14th, 2006 at 0:23
Hi Robert,
I am currently experimenting with “custom” namespaces and have discovered that the interface in Firefox is a little unsatisfactory. For instance in IE, with the properties scopeName and nodeName, I can find out contextual information about a certain element.
In Firefox, scopeName does not exist at all (but I have extended as seen below) and nodeName returns both the namespace and the nodeName, united by a colon…in upperCase.
Node.prototype.__defineGetter__(‘scopeName’, function() {
var nn = this.nodeName.toString();
return (nn.indexOf(‘:’) > -1)? nn.split(‘:’)[0].toLowerCase() : ‘HTML’ ;
});
I find the Firefox interface poor and limiting. But than again, I might be missing out on something…so I hope you shed some light to the subject. Do you know any way to extract the properties of an element in a suitable way in Firefox?
BR,
/hbi
September 14th, 2006 at 12:26
Hakan,
Unfortunately, I don’t have an answer for you. I never get time nor assigned to play around with such fun stuff!
September 14th, 2006 at 16:57
Ok…thanx anyway.
/hbi
October 21st, 2006 at 20:59
Works great in firefox and opera but not at all in IE6 for my implemention.
But as it’s the class I wanted I found your getElementsByClassName which worked fine in all 3 browsers.
October 22nd, 2006 at 21:29
Simon,
Weird… I use it all the time and haven’t ahd any problems with IE 6. For example, with my GLT library it’s vital.
November 5th, 2006 at 18:43
What I’m trying to do is find all instances of inline styles and remove them.
However, it seems that the attribute ‘style’ does not get returned in IE. I’ve tested in other browsers and the ‘style’ attribute is found, but IE, the array is returned empty.
Any thoughts on how to make this work?
November 5th, 2006 at 19:54
It’s seems I may have found a solution, however, not so graceful.
Due to the way IE works, when trying to get the ‘style’ attribute, IE’s getAttribute function returns an object.
The work around I found was to set the oAttribute variable using the .cssText property for IE. I believe that the ‘style’ attribute is the only attribute stored as an object in IE. I could be wrong though…
My modification to your function:
/*
Copyright Robert Nyman, http://www.robertnyman.com
Free to use if this text is included
*/
function getElementsByAttribute(oElm, strTagName, strAttributeName, strAttributeValue){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var oAttributeValue = (typeof strAttributeValue != "undefined")? new RegExp("(^|\\s)" + strAttributeValue + "(\\s|$)") : null;
var oCurrent;
var oAttribute;
for(var i=0; iif(typeof oAttribute == "object"){
oAttribute = oAttribute.cssText;
}
if(typeof oAttribute == "string" && oAttribute.length > 0){
if(typeof strAttributeValue == "undefined" || (oAttributeValue && oAttributeValue.test(oAttribute))){
arrReturnElements.push(oCurrent);
}
}
}
return arrReturnElements;
}
November 5th, 2006 at 20:10
Ok, so, my code broke Firefox. This is dirty, but works.
if (navigator.appName == 'Microsoft Internet Explorer')
{
oAttribute = oAttribute.cssText;
}
November 6th, 2006 at 9:56
Matthew,
Interesting. However, the way I see it,
styleisn’t really an attribute in that sense. You never set a style throughsetAttribute, but instead by using the.stylenotation.If your code works in your case, I’m happy for you, but I don’t find it necessary to incorporate in the standard version of the script.
A little suggestion: Instead of checking for web browser name, you can use
if(document.all)and then a check forif(typeof oAttribute.cssText != "undefined).November 7th, 2006 at 12:24
[...] d, if you want to, a certain value in that attribute as well. More thoroughly described in Monday code giveaway: getElementsByAttribute. preventDefau [...]
November 12th, 2006 at 1:50
Thanks for the tip and thanks again for the script!
-mk
November 13th, 2006 at 9:00
Matthew,
No problem at all! I hope everything works out for you.
December 1st, 2006 at 23:00
Okay, so I’m wondering if someone could kindly help me with this a bit. Long story why, but in essence I want to find the ID of a single div element among many which have been dynamically generated in javascript (each element is assigned an ID along the lines of cell_1_2, cell_1_3, etc). That element has a unique style (a background color) and is the only element belonging to a specific class (called “highlighted”).
I’m not sure if this is the right function, or if getElementByClass is better, but in either case I’m having a hard time returning the ID of that single element.
Any thoughts? Much appreciated …
February 3rd, 2007 at 19:19
Hi, this code works great. However i’ve found something that causes it not to work properly.
when i create a “input” form control without specifying the type, it defaults to type=”text”. your current script is not able to work with this “lazy” coding
February 25th, 2009 at 14:28
[...] Monday code giveaway: getElementsByAttribute – Robert’s talk – Web development and Internet tr… [...]
April 7th, 2009 at 12:44
[...] fuera de un framework como jQuery o Mootools. Actualmente existen unas cuantas escritas como la de Robert Nyman y la incluida en el diccionario XUL de desarrollo de extensiones para [...]
June 13th, 2009 at 7:57
[...] getElementsByAttribute [...]
April 29th, 2010 at 14:25
Robet u did a grat job, really a very helpful example indeed
Write a comment
Twitter reactions