The Ultimate getElementsByClassName
Tweet Follow @robertnymanNew version released, with major updates Tuesday, May 27th, 2008.
NOTE: The code below is outdated.
A completely rewritten version of getElementsByClassName has been released, taking into account all new available web browser features and possibilities, to offer you the best performing and most flexible implementation. Read about the new version or go and download it straight away.
Updated on Tuesday, November 8th, 2005.
Updated again, Tuesday, November 8th, 2005
Switched from using word boundaries to checking for spaces and/or start/end of string. Also, see my comment about this.
Once again updated Tuesday, November 8th, 2005
I forgot a break; statement in the advanced version. Nothing that would break it, but bad performance-wise.
Updated Tuesday, November 8th, 2005
This is getting ridicilous now. Changed name of the linked JavaScript file to getElementsByClassName.js.
Updated July 14th 2006
As Wilfred and Sander correctly pointed out, there is a way to make the script more efficient in IE 5.x when using the wildcard character to call it. The code in this post and the downloadable file have been updated accordingly.
Updated May 11th 2007
It’s been a while since I took a look at this, and with speed comparisons and all, I have revised so it should be just a tad faster. The new script is just below and added to the downloadable JavaScript file as well.
One of the major differences is that tag name and containing element are optional, and if not supplied, will default to * respectively document. This means that the order of the parameters are also changed, so className to look for is the first one, followed by tag and then elm. However, for best performance, I recommend sending in all three parameters as closely specified as possible.
Updated May 30th 2007
The revised version in the file was ok, but the published version in the post just below missed a couple of \. This has now been adressed.
Revised version May 11th 2007
function getElementsByClassName(className, tag, elm){
var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
var tag = tag || "*";
var elm = elm || document;
var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
var returnElements = [];
var current;
var length = elements.length;
for(var i=0; i<length; i++){
current = elements[i];
if(testClass.test(current.className)){
returnElements.push(current);
}
}
return returnElements;
}
Good JavaScript usage on the Internet is based on making it unobtrusive, meaning that web pages aren’t dependant on it to work and that that the HTML code shouldn’t be riddled with inline event handlers and JavaScripts. Using javascript: is forbidden, stop that!
What you do is to apply the events to desired elements from an external JavaScript file, normally performed when the page has loaded. For instance, if you want to apply a certain event to some a elements, you loop through the a elements in the page and then apply the events accordingly, e.g. if the element has a certain class name.
Last week, I felt the need to have a script that accessed all elements in a web page with a certain class name and returned them as an array to work with. I wrote my function, but ran into problems when it came to distinguishing class names that contained a hyphen (-). Then I remembered that Jonathan Snook wrote a function a while ago, so I went to his web page to see if I’d missed something. Interestingly enough, it was very similar to mine, and when I tested his it didn’t work either.
So, since Jonathan and I talk on and off, I contacted him about this over MSN. Jonathan, being the cool and helpful guy that he is, immediately took the time to discuss this with me. I coded away, told him what happened as I went along, and we brainstormed about how we could solve it. After some work, we came up with something that seems to work really fine, supporting class names with hyphens and multiple class names on the same element. It is actually very similar to Jonathan’s original function but with an escape fix and some performance add-ons.
Let me present The Ultimate getElementsByClassName:
/*
Written by Jonathan Snook, http://www.snook.ca/jonathan
Add-ons by Robert Nyman, http://www.robertnyman.com
*/
function getElementsByClassName(oElm, strTagName, strClassName){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
strClassName = strClassName.replace(/\-/g, "\\-");
var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
var oElement;
for(var i=0; i<arrElements.length; i++){
oElement = arrElements[i];
if(oRegExp.test(oElement.className)){
arrReturnElements.push(oElement);
}
}
return (arrReturnElements)
}
Some ways to call it
- To get all a elements in the document with a “info-links” class.
getElementsByClassName(document, "a", "info-links");- To get all div elements within the element named “container”, with a “col” class.
getElementsByClassName(document.getElementById("container"), "div", "col");- To get all elements within in the document with a “click-me” class.
getElementsByClassName(document, "*", "click-me");
The first line in the function is to cover-up for a flaw in IE 5 where one can’t use the wildcard selector * to get all elements. The rest is basically about setting up a regular expression with the class name we’re looking for, where we escape hyphens and then match that to the class names of the elements where we’re looking for it.
Please try it out. Our hope is that it will help you develop unobtrusive JavaScripts and that it will make it easier for you to maintain your web sites. Any problems with the function, please let us know.
Go crazy now!
Updateded! Since Anne asked for support to look for multiple class names in the same call, I’ve revised the function. The above function is intact and supports multiple class names if they’re entered in that order on the element. If they’re not, you should use the below function. Kudos to Curtis for inspiration.
function getElementsByClassName(oElm, strTagName, oClassNames){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var arrRegExpClassNames = new Array();
if(typeof oClassNames == "object"){
for(var i=0; i<oClassNames.length; i++){
arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames[i].replace(/\-/g, "\\-") + "(\\s|$)"));
}
}
else{
arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames.replace(/\-/g, "\\-") + "(\\s|$)"));
}
var oElement;
var bMatchesAll;
for(var j=0; j<arrElements.length; j++){
oElement = arrElements[j];
bMatchesAll = true;
for(var k=0; k<arrRegExpClassNames.length; k++){
if(!arrRegExpClassNames[k].test(oElement.className)){
bMatchesAll = false;
break;
}
}
if(bMatchesAll){
arrReturnElements.push(oElement);
}
}
return (arrReturnElements)
}
Ways of calling the function now are:
- To get all a elements in the document with a “info-links” class.
getElementsByClassName(document, "a", "info-links");- To get all div elements within the element named “container”, with a “col” and a “left” class.
getElementsByClassName(document.getElementById("container"), "div", ["col", "left"]);
Note that you can still use a string when only looking for a single class name, but an array when looking for multiple class names.
Also, if this is to work in IE 5.0, you need to include this add-on to get support for the push method on the Array object:
if(typeof Array.prototype.push != "function"){
Array.prototype.push = ArrayPush;
function ArrayPush(value){
this[this.length] = value;
}
}
If you don’t like to read the code here, you can download the JavaScript file.

245 Comments
November 7th, 2005 at 13:33
Nice! Support for IE5 is more than I'd have ever asked for
Btw, The design rocks
November 7th, 2005 at 13:43
[...] services with TiVo ZDNet UK: DoS attacks: The plague for our times? Robert’s talk: The Ultimate getElementsByClassName Digitoday: Oikotie oikoi mutkia [...]
November 7th, 2005 at 13:53
Looks nice Robert, of course i will try it out!
// Jorkas
November 7th, 2005 at 16:03
The ultimate would be to use a JavaScript library – like http://www.mochikit.com/ or http://prototype.conio.net/. They offer similar functions + a lot more
November 7th, 2005 at 20:17
[..] tion like this in the past but was too lazy to write it. Should make my life easier. Ultimate getElementByClassName� [.]
November 7th, 2005 at 20:36
Rowan, Jorkas,
Thanks!
amix,
Well, personally I don’t like using JavaScript libraries. Normally, they’re too bloated, and even if they’re not, it’s pretty much guaranteed that they will contain more code than needed.
And from MochiKit’s web page:
To me, it’s mandatory to make sure scripts work in IE 5 as well as earlier version of Mozilla-based web browsers like Firefox. Also, previously released versions of Safari are known to have some JavaScript issues.
Curtis,
Well, I can’t be on call all the time!
Thanks, Zilla, for the trackback then!
I tried that, but for some reason it didn’t work (although it should). Another way of putting it is
"(^|\s)"+etc.Anyway, word boundaries seems like the most correct approach, and since this seems to work fine, I didn’t investigate it further.
andr3,
That’s cool. I’m sorry you don’t like the layout, but I hope I can still write posts that are interesting enough to lure you back here!
Squint your eyes real hard and just focus on the white part with the text.
Anne,
Yes, of course it works with multiple class names. Otherwise it wouldn’t be of much use now, would it?
November 7th, 2005 at 22:21
Instead of escaping the hyphen couldn't you use the RegExp <code>"(^| )"+strClassName+"( |$)"</code>?
Also, it looks like amix forgot to close his anchor tag which made it nearly impossible to post this comment, lucklily the trackback from Zilla Smash ran interference.
November 7th, 2005 at 22:28
Robert!
Thank you both for doing this!
I'll give this a test-drive and if i run into some relevant issues i'll get back to you.
—
And since this is my first comment here since the redesign, i think i have to be honest with you (i'd like that if i had just redesigned my site). I'm not feeling this layout that much man. I'm sorry. Maybe it's the slightly pixeled image on top… I know it's being stretched, but that's exactly the problem. This is probably just me.. i just couldn't go without saying anything.
(this probably should go in the other post. sorry)
November 7th, 2005 at 22:30
Does this take multiple class names into account? (See the <code>getElementsByClassName</code> definition in HTML 5.) If not, not sure if this is the ultimate solution
November 7th, 2005 at 23:02
Hmm… I have used that regexp in my own version of getElementsByClassName for a while now and haven't run into any problems.
And while I don't want to speak for Anne — apparently he doesn't like that
— I believe he means multiple classnames in the function call as outlined in Web Applications 1.0
November 7th, 2005 at 23:32
Curtis,
Yes, I don't know why it didn't work in my testing. Weird. But the word boundaries work!
Regarding Anne's comment, I just came back to the computer, thinking about it. I just tested it, and it works like a charm!
Only thing then is that the class names have to be in that order that you ask for them. For instance:
<code>getElementsByClassName(document, "a", "info-links left");</code> will match <code><a class="info-links left">A tag</code>, but it won't match <code><a class="left info-links">A tag</code>.
Not too much of an issue, if you ask me. If you use several class names on different elements, it feels pretty sensible to apply them consistently on all elements.
November 8th, 2005 at 1:00
So it does not work. Thanks for clarifying. (Think of class names inserted randomly by some generator, you can not rely on order.) I already thought it did not cope with that as it seems you are checking the input against the value of the <code>className</code> DOM attribute. I only took a brief look at the code so therefore I asked.
November 8th, 2005 at 1:18
Anne,
No problem.
However, I don't think it would be to hard to tweak the regular expression to check for that too. But that's work for another day…
November 8th, 2005 at 5:38
I took a stab at matching, at least functionally, the getElementsByClassName described in Web Applications 1.0. I assume I interpreted the spec correctly — albeit loosely — and have come up with a solution, but then you know what happens when one assumes.
Because it allows multiple classnames to be passed as either an array or space delimited string it should be completely backwards compatible with your function above (and many other implementations that follow that param pattern). It's a quick attempt and hasn't been thoroughly tested or optimized, so tear it apart and let me know what you find.
November 8th, 2005 at 5:45
I take that back about being backwards compatible with your function above, I swapped the classname and tagname parameters to allow tagname to be omitted. Would be an easy modification however if backwards compatability was necessary.
November 8th, 2005 at 11:54
Curtis,
Damn it, I thought about this during the morning and just sat down at the computer to code it. Of yourse you had to do it then!
Your solution was pretty identical to mine. I've updated the post with an alternative where it works. Thanks for the inspiration!
November 8th, 2005 at 13:33
Regexp with word boundaries will match 'info-links-big' while searching for 'info-links' (hyphen is considered as word boundary), while it shouldn't.
November 8th, 2005 at 15:21
Bruce,
Thank you for that invaluable feedback!
The scripts and the post are now changed to using <code>"(^|s)"</code> and <code>"(s|$)"</code> instead.
Also, I found out why that approach didn't work for me before: the check for spaces and start/end fo string has to be enclosed within parentheses when creating the RegExp object.
November 8th, 2005 at 20:47
Sorry Robert, I was stuck at the office yesterday and gave it a shot. Our solutions are very similar but…
* since you are no longer using word boundaries, why escape the hyphens?
* once one RegExp match fails there is no reason to check the remaining, so <code>break</code>ing out of the loop might save a wee-bit of time.
Also I see you are requiring multiple classnames to be passed as an array, which is probably a closer interpretation of the spec but I just like the syntactic sugar of passing a space delimited string (which looks as though is still be debated within WhatWG). All-in-all I think we have a pretty good solution here, but I am hoping Anne chimes in to confirm/deny this.
November 8th, 2005 at 20:51
Apparently I have too much time on my hands, but I noticed you named the JS file getElementsByTagName.js, I assume that is a mistake? Oddly enough I did the same thing yesterday.
November 8th, 2005 at 22:14
Curtis,
It's ok.
I haven't actually tested without escaping the hyphens, but I was afraid that it wouldn't work since hyphens have a special meaning in regular expressions (setting a span of characters to look for, e.g. A-Z).
I was apparently sloppy; of course there should be a <code>break;</code> statement there. It's added in the code and post now.
I thought a little about using a space delimited string and splitting it into an array, but just figured this was a more correct approach.
However, I do agree that if Anne's reading this, it would be interesting to hear WHATWG's opinion about this.
It's totally ok with your comments, I really like this constructive discussion!
I did name the file that. Maybe I'm missing something here, but why wouldn't it be appropriate? If it becomes a built-in function in the future or because it's the name of the function?
November 8th, 2005 at 23:03
Shouldn't it be getElementsByClassName.js instead of getElementsByTagName.js?
Good, me too.
November 8th, 2005 at 23:43
A hyphen only has special meaning for RegExp when used in a character class, [].
I didn't realize this at the time, but by not escaping hyphens–or any special characters–you could use a regular expression pattern for the classname.
Example using my getElementsByClassName:
* <code>getElementsByClassName(document, '.+-.+');</code> would match any element belonging to any hyphenated class.
* <code>getElementsByClassName(document, "b{3}.*");</code> would match any element belonging to any class beginning with "bbb".
An interesting side-effect, but could introduce some bugs, although no other valid className characters (unresearched) immediately come to mind that have special meaning within RegExp.
November 9th, 2005 at 0:04
Curtis,
Ha ha! That is freaky!
Force of habit, I guess…
Interesting. For now, I think I'll leave the hyphens in there, but when I feel crazy, I'll remove them and test it thoroughly.
Interesting, though, to pass in a regular expression looking for class names. Probably overkill, but cool!
November 9th, 2005 at 16:25
<blockquote cite="http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/#comment-1573">andr3,
That’s cool. I’m sorry you don’t like the layout, but I hope I can still write posts that are interesting enough to lure you back here!
Squint your eyes real hard and just focus on the white part with the text.
Man, that's something i'm not worried about… I'm not going anywhere. Not with the quality of such posts like this one. You rawk!
Great job you guys. Haven't had time to try it though.
But i'll definately use it in the future.
November 9th, 2005 at 16:34
andr3,
Thank you, I'm happy to hear that!
November 10th, 2005 at 1:14
Does it come with an 'update available' link included
November 10th, 2005 at 11:27
Steve,
Ha ha! Hopefully it works now and shouldn't need any more updates.
The only thing I can think of, off the top of my head, is to try and remove the escaping of the hyphens. But it shouldn't be necessary, and for now I keep them in there to play it safe…
November 10th, 2005 at 15:39
[...] tes where you can download some of the top designs from OSWD: (tags: oswd templates) Robert’s talk » The Ultimate getElementsByClassName After some wor [...]
November 11th, 2005 at 0:33
Robert,
Great work. The only thing I would love to see would be adding this to the DOM interfaces. Basically, I'd like to see:
<code>
document.getElementById("SomeElement").getElementsByClassName( "div", "someclass" )
</code>
Now, that would be cool.
November 11th, 2005 at 18:39
Adam,
From the top of my head, you can use this in Mozilla web browsers:
<code>
HTMLElement.prototype.getElementsByClassName = function (strTagName, strClassName) {
getElementsByClassName(this, strTagName, strClassName);
};
</code>
However, I'm not sure if this works in Safari or how to accomplish it in IE without looping through all the elements and adding the method to them.
November 13th, 2005 at 16:46
Instead of using <code>"(^|s)" + strClassName + "(s|$)"</code> might I suggest <code>"" + strClassName + ""</code>.
November 13th, 2005 at 23:20
John,
No, you might not!
Seriously, though, I was using word boundaries at first, it seemed like a more elegant approach. But as Bruce pointed out, it became an issue when using hyphens in class names.
November 19th, 2005 at 17:38
[...] ma entrega… Comenzamos con cosas de Javascript y DOM… En Robert’s Talk, una funci�n ge [...]
November 20th, 2005 at 0:32
This is good. Why isn't there a getElementsByClassName in JavaScript by default? Did the developers do getElementsByID one day and get tired, so they just forgot it?
November 23rd, 2005 at 20:42
oh, sorry about the code!
You can see how I’m using it at
this sample page.
November 23rd, 2005 at 20:44
sorry, I should also say that my sample page is based on another sample page, first linked from a web design thread in flickr.
November 23rd, 2005 at 20:59
Anything wrong with doing things this way instead?
function tagHasClass(theTag, theClass)
{
var returnValue = false;
var allClasses = theTag.className.split(" ");
for(i=0;i
November 23rd, 2005 at 21:17
Ed,
Thanks!
I have no idea why it wasn't included initially with getElementById and the rest.
Regarding your code example: I'm not really sure what you were going for, but if you want to have code in a comment, please remember to escape < with < and > with >.
November 23rd, 2005 at 23:10
Ed,
No problem.
And sure, splitting class names can also be an approach.
November 28th, 2005 at 19:41
WOW!
Great script! just what I was looking for.
I've tested it on Konkeror 3.4.3 and it works perfectly!
From now on, I'll come here from time to time
November 28th, 2005 at 19:45
lamberete,
Thanks!
December 12th, 2005 at 11:19
What is the difference/advantage of this method over something like Simon Willison's getElementBySelector?
December 12th, 2005 at 11:50
christian,
Well, I haven't studied Simon's getElementBySelector carefully, so he'll have to excuse me if I'm incorrect here.
First, this function is more light-weight
Second, if I'm not mistaken, his function loops through all the elements in the document for every check, which can decrease performance, especially when it comes to a large document.
Third, I just find this to be a more easily understood approach than sending selectors as a parameter to the function.
December 13th, 2005 at 10:17
Robert,
Your points are well taken. I particularly agree with you on the 2nd.
Still, there is something to be said for the specificity of using selectors as opposed to just a class name.
This seems like a case of picking the right tool for the job.
Thanks for adding to the toolbox.
December 13th, 2005 at 11:44
christin,
Absolutely, I agree. The power of specificity should definitely not be underrated.
December 29th, 2005 at 1:18
how can i override the prototype version of this with yours?
December 29th, 2005 at 12:07
louis w,
I'm not sure how prototype is built up, but I guess you can just include my JavaScript file separately or include the <code>getElementsByClassName</code> function within the prototype JavaScript file.
January 21st, 2006 at 17:21
louis w,
In prototype, <code>getElementsByClassName</code> is a method added to the document element. Robert's is a standalone function. If I'm not mistaken, the two following calls return the same array:
<code>getElementsByClassName(document, '*', 'foo');</code>
<code>document.getElementsByClassName('foo');</code>
January 23rd, 2006 at 11:21
Chuck,
Yes, I believe those two will be the same.
January 24th, 2006 at 23:19
getElementsByClassName [...]
January 29th, 2006 at 18:45
[...] commentaire » Un Back to top. » The Ultimate getElementsByClassName.  Catégories: java [...]
February 4th, 2006 at 19:23
Congratz Robert
You're on stylegala in the news section!
February 4th, 2006 at 23:35
Henrik,
Thanks! Actually, I have two items on Stylegala's first page for the moment…
A very rare thing, I know!
I've been on it a couple of times, but it's an honor each time.
February 6th, 2006 at 12:15
[...] älkomnas. Metoden för att välja ut element kan också förbättras. Robert Nyman har en getElementsByClassName funktion som man kan implementera.
Det här inl&aum [...]
February 6th, 2006 at 22:39
With my getElementsByClass I wrote a few months back, I switched the order of the names for cases of when the developer wishes not to declare a tagName or a parentNode. It seems more practical that way. Other than that, it's nice to add another getElementsByClassName to the growing pile.
As you can see, you, snook, and myself are all using the same RegExp
February 7th, 2006 at 0:03
Dustin,
Ah, right, it seems to be popular!
February 19th, 2006 at 1:51
You should add support for Moz's XPath which will greatly speed things up.
February 20th, 2006 at 11:39
David,
That's an interesting idea, and I might do that in the future. Personally, I'm a big fan of XSLT and XPath, so I'm really happy with where things are going.
February 22nd, 2006 at 21:26
One system we've setup is using css selectors, such as
getElementsByClassName("div.myclass")
February 23rd, 2006 at 12:08
Micah,
Yes, I know people who prefer that approach. Personally, I prefer the one in the script above, since it feels more clear from a programmatical point of view as opposed to thinking CSS selectors.
March 22nd, 2006 at 1:10
HI!
Great function! (it's a bit sad that you cannot add it to the Element.prototype, it would be nearly "perfect")…
just a curiosity…
why you didn't use the Element.all property to speed up search in case of IE?
March 22nd, 2006 at 10:53
Diego,
Thank you!
You mean instead of <code>getElementsByTagName</code>? I wanted to use standard DOM methods as far as possible, and I haven't experienced any performance lack because of that.
March 23rd, 2006 at 5:56
Thank you, thank you, thank you. This function solves a major problem I've been having . . . and it makes my life so much easier. Awesome function!
March 23rd, 2006 at 10:54
Jimmy,
No problem, I'm glad it helped!
March 23rd, 2006 at 14:38
[...]getElementsByClassName [...]
March 29th, 2006 at 18:31
[...] ’s version and then shaped by valuable feedback from talented people (please see the ultimate-getelementsbyclassname) , if(typeof whatEver != “undef [...]
March 30th, 2006 at 1:17
I like it, BUT…
I think the argument order is all wrong. I doubt that you will change it (who wants to break everyones code?), but I think that it could really benefit as far as actually using the function and using it quickly.
For instance, I would venture to say at least 90% of the time people use this, they want to search for all tags by a certain class in the document.
So why have the most used part of the function as the last argument?
If I had my druthers, the argument order would look something like this:
getElementsByClassName(oClassNames, strTagName, oElm );
Why? Because I think it should go in order of frequency of use, as well as specificity.
oClassName will get you every element with that class in the document.
strTagName will get you the specific tags with that class in the document.
and oElm will let you narrow your search even further by specifying the element to search in.
I would just have strTagName default to * and oElm default to document.
This way, if you only want to grab everything in the document with a certain class you just say:
getElementsByClassName('testClass');
and if you want to narrow it even further, you can add specific parameters.
Okay, that's a lot of rambling
Good work even with my gripes
March 30th, 2006 at 11:40
Nate,
I agree with you points, very valid ones. However, I guess one good thing that can come out of having to specify a tag name and what element to look in is to force people to think more about performance.
As you said, though, I won't change it!
But, in the end, the function's here for people to tweak and use whichever way they want to, so feel free to adapt it to your own personal preferences and needs.
March 30th, 2006 at 11:45
I've tried to use this code, but when passing the resulting list to a function, I get an error message when running getAttribute on one of the elements. There's a thread over at CodingForums, but maybe someone here has had a similar experience?
March 30th, 2006 at 11:59
l0b0,
I just took a very quick glance at the code but didn't directly see why it didn't work. <code>getElementsByClassName</code> just returns an <code>array</code> of elements, so the problem seems to lie in your <code>toggle</code> function.
What if you made the array helpElements into a global variable and then referenced it?
March 30th, 2006 at 14:08
l0b0,
I’m sorry, but that hasn’t got anything to do with what’s returned from
getElementsByClassName: they are just pure object references.Try working with that
arraydirectly; loop throgh it and just alert what you have in every position and you will see it.March 30th, 2006 at 16:04
Robert,
There's been some progress, but I'm still in the dark. The objects passed from getElementsByClassName don't seem to be referencing the elements in the DOM once passed to a function; I only get "undefined" for properties such as nodeName and parent.childNodes.length.
April 9th, 2006 at 4:31
Awesome script! Can you tell me what the license is on this? I'm including a credit comment at the top of the script before I use it, and I'd like to note any license terms there as well.
April 9th, 2006 at 21:18
Adam,
Thanks!
The credit comment is all it takes, no license. Go crazy with it!:-)
April 15th, 2006 at 19:06
Duly noted, Robert, and thanks for the reply.
Those who find this script useful might also be interested in something the guys at Mad4Milk recently cooked up: moo.dom, a slim bit of JavaScript that pretty much lets you go crazy with simple CSS selectors and tack on actions to the selected elements in one fell swoop. The demo page they created gives you a pretty good idea of how it works in practice.
The drawback of moo.dom is that it’s a bigger script than Robert’s “Ultimate getElementsByClassName,” especially when you factor in the requirement of a stripped-down version of
prototype.js. The total file weight ofmoo.dom.js+prototype.lite.jsis just under 6 KB. By comparison, the second version of Robert’s script is about 1.3 KB with the IE5 compatibility patch included.Basically, moo.dom is good if you’d like a somewhat more intuitive selection syntax married to easily-added actions or effects and your page isn’t already too heavy with script. If you want something more lightweight that can easily be incorporated into your own scripts instead of acting as a one-shot solution, then Robert’s script is a better bet.
April 15th, 2006 at 22:13
Adam,
Thanks for the tip!
April 18th, 2006 at 0:18
I love it!
I almost always write my code myself, thou this can not be improved and should not be modified. (:
Thanks!
April 18th, 2006 at 10:48
gorbiz,
Thank you!
May 1st, 2006 at 14:46
[...] les and then decided to do my own version for fun. Out of all of the functions I looked at Robert Nyman’s came closest to what I wanted (kudos!) but my ver [...]
May 4th, 2006 at 11:44
[...] IE/Win 5+, IE/Mac 5.2+, Firefox 1.0+, Opera ?, Safari ? * getElementsByClassName (parent, tag name, class name) &n [...]
May 13th, 2006 at 13:50
[...] ’s version and then shaped by valuable feedback from talented people (please see the [...]
May 16th, 2006 at 14:57
I realise that escaping class names has been discussed previously, but the String.prototype.replace call is still present. Whilst class names may contain special characters, from the perspective of the regular expression, a hyphen isn’t one of them.
On a different subject, at the very least,
<code>Array.prototype.push = ArrayPush;
function ArrayPush(value){
this[this.length] = value;
}</code>
should be replaced with:
<code>Array.prototype.push = function(value){
this[this.length] = value;
};</code>
The introduction of an identifier is unnecessary. However, this is still undesirable as it unconditionally substitutes a native implementation for an inferior alternative.
Better would be:
<code>if (typeof Array.prototype.push != 'function') {
Array.prototype.push = function(value){
this[this.length] = value;
}
}</code>
Better still (in my opinion):
<code>if (typeof Array.prototype.push != 'function') {
Array.prototype.push = function(v) {
var i = this.length >>> 0,
j = 0;</code>i
while(j
The latter behaves exactly as described in section 15.4.4.7 of ECMA-262, 3rd Ed.
Mike
May 16th, 2006 at 15:03
Oops. Let’s try that again.
<code>if (typeof Array.prototype.push != 'function') {
Array.prototype.push = function(v) {
var i = this.length >>> 0,
j = 0;</code>
<code> while(j < arguments.length) {this[i++] = arguments[j++];}
return this.length = i;
};
}</code>
Apologies,
Mike
May 25th, 2006 at 16:59
<code>function getElementsByClassName( _tag, _class, _scope){
var regexp, classes, elements, element, returnElements;</code>
<code>_scope = _scope || document;</code>
<code>elements = !_tag || _tag == "*" ? document.all : _scope.getElementsByTagName(_tag);
returnElements = [];</code>
<code>classes = _class.split(/s+/)
regexp = new RegExp("(^|s+)("+ classes.join("|") +")(s+|$)","i")</code>
<code>if(_class){
for(var i=0; element = elements[i]; i++){
if(regexp.test(element.className)){
returnElements.push(element);
}
}
return returnElements;
}else{
return elements;
}
}</code>
Usage:
var inps = document.getElementsByClassName("div", "menu menu-top", $("menu"))
July 20th, 2006 at 1:39
anybody use this script with opera 9 ? for me it doesn't work.
July 21st, 2006 at 14:24
Robert (or as you are on leave, Anyone),
a co-worker spotted a possible mistake. We think that
<code>
var arrElements = (strTagName == "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);
</code>
Should be:
<code>
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
</code>
As that it should only search in the original context, not the whole document..
just our four (2×2) cents
Wilfred and Sander
July 24th, 2006 at 15:46
I may be mistaking, but the use of document.all in the script suggests it only works in explorer, doesn't it ? if so, it's not quite ultimate yet
July 24th, 2006 at 15:56
Michael Winter,
Thanks for your suggestion.
André,
You're welcome to take a stab at your own implementation anytime.
goetsu,
For me it works in Opera 9, so you might have some error in the way you call it.
Wilfred and Sander,
You are absolutely right! Thanks for pinting that out, the post and the code has been updated! Now it should be more efficient for for IE 5.x as well.
pike,
It only uses <code>document.all</code> for IE 5, since IE 5.x has a flawed implementation where it doesn't support the wildcard character. As it says in the post:
August 1st, 2006 at 22:05
Chi-Wai Lau,
The second function in the post should work with multiple class names; at least it does so for me. Make sure that's the one you're using.
Good luck!
August 2nd, 2006 at 0:18
Chi-Wai Lau,
You need to escape HTML characters, i.e. < for < and so on.
But I get your drift how you made it work, but I don't know why the function doesn't work in the first place for you then.
Did you make sure you're using square brackets around the multiple class names, to create an array? It should look something like this:
<code>["col", "left"]</code>
August 2nd, 2006 at 0:38
Chi-Wai Lau,
No problem.
Hmm, if c1 and r1 are variables that just contains strings, then it should work… If that's not the problem, then I'm sorry, I can't figure out what it would be.
August 2nd, 2006 at 1:13
Chi-Wai,
I just tested in Safari 2.0.4 and it worked fine for me, and it also worked if I specified variables and then used them in the function call. What happens when you try it? Do you get an error, or is the length just 0 for the array returned?
I also recommend that you try it in Firefox and check the JavaScript Console there for eventual errors (Tools > JavaScript Console).
August 21st, 2006 at 7:44
[...]- Risk the game! I cant wait for the multiuser ver. (tags: ajax api web2.0 google game) The Ultimate getElementsByClassName Why this d[...]
August 31st, 2006 at 22:41
[...] ts which may be a combination of XPath, XQuery, CSS syntax, and simple new methods such as getElementsByClassName. Add/Remove Class Prototype has it, JQuery [...]
September 25th, 2006 at 13:57
Rovert,
Thanks for putting this online – saved me a bunch of headaches and time. Clean, simple and efficient. Hurray for sharing.
–S.B.
September 25th, 2006 at 13:58
Robert,
Thanks for putting this online – saved me a bunch of headaches and time. Clean, simple and efficient. Hurray for sharing.
–S.B.
Doh: Typo in your name. Shame on me. Feel free to remove previous post.
September 25th, 2006 at 15:10
Sander,
I'm glad it helped. And don't worry about the spelling…
October 3rd, 2006 at 22:27
Thank you for this, its support on IE is really great!
October 3rd, 2006 at 23:40
Vlad,
No problem, I'm happy you like it.
October 17th, 2006 at 1:30
This isn't working for multiple class names on one element:
class='note nopromo'
Maybe this line could be changed:
var pattern = new RegExp('(^|s)' + searchClass + '(s|$)');
I'm a bad regex-er, or I would offer a solution.
October 17th, 2006 at 10:51
Matt,
It works if the element has multiple class names, but it doesn't support looking for several class names with the same call.
October 30th, 2006 at 20:49
[...] e instead of the built in one provided by prototype was created by Robert Nyman called the Ultimate getElementsByClassName. He’s done a great job explainin [...]
October 30th, 2006 at 20:49
[...] e instead of the built in one provided by prototype was created by Robert Nyman called the Ultimate getElementsByClassName. He’s done a great job explainin [...]
November 7th, 2006 at 12:23
[...] A function to get all elements with a certain class name. More thoroughly described in The Ultimate getElementsByClassName. addClassName/dt A functio [...]
November 15th, 2006 at 1:38
How about adding wildcard support to the class names ?
November 15th, 2006 at 10:17
Andy,
I've thought about it, but didn't find it that important of a feature. Naturally, though, you can easily tweak the script if you want that.
November 20th, 2006 at 22:47
Yeah well, I discovered that it worked fine using regex statements so that's alright.
November 21st, 2006 at 10:42
Andy,
Ah, good.
November 23rd, 2006 at 14:41
[...] JavaScript com diversas implementações. Aprecio as versões de vários autores como a do Robert Nyman e a do Dustin Diaz, porém prefiro utilizar uma que dese [...]
November 28th, 2006 at 18:48
Good function!
But doesn't work on IE 5 Mac…
My IE 5.1 Mac doesn't support array.push() so i replace the push method by
array[array.length] = new regexp…
Now its working…
The returned elements are ordered Desc so you need to reverse it
BTW IE 5.2 is supporting Array.push()?
thx
SImon
November 28th, 2006 at 20:55
Couldn't get it to work when using arrays. Wrote this for-loop instead:
<code>
for(var j=0; j<arrElements.length; j++){
oElement = arrElements[j];
for(var k=0; k<arrRegExpClassNames.length; k++){
if(arrRegExpClassNames[k].test(oElement.className)) {
arrReturnElements.push($(oElement));
break;
}
}
}
</code>
November 28th, 2006 at 23:14
Simz,
In the end of the post, there's code for implementing support for <code>push</code> in IE 5.
December 18th, 2006 at 22:07
worked great! thanks!
January 25th, 2007 at 23:43
you could also use <code>""+strClassName+""</code> for the regular expression
(bareword) will match word boundaries as well as the beginning/end
reference
January 26th, 2007 at 0:46
Sorry, make that: <code>"b"+strClassName+"b"</code>
January 26th, 2007 at 0:50
Soylent,
As mentioned at the top of the article, word boundaries won't work when there are hyphens in a className.
January 26th, 2007 at 0:51
Okay, this thing is killing my double backslashes. So, that should be 2 backslashes before the b.
February 2nd, 2007 at 17:39
[...] updated to reflect that changes that’ve been made. getElementsByClassName has long been a mainstay of web developers everywhere – and by making it official (bot [...]
February 3rd, 2007 at 3:05
[...] ClassName como parte de su core. Esto es una gran noticia ya que no tendremos que realizar el apaño mediante javascript y dispondremos de una funcionalidad inte [...]
February 5th, 2007 at 0:33
[...] entsByClassName. Fingers crossed the other browsers follow suit soon, so we can stop using 20 li [...]
February 10th, 2007 at 21:07
Robert,
a very useful bit of code – thanks to it, I've managed to put together a method of expanding elements vertically.
Thanks!
February 23rd, 2007 at 12:32
does anyone know how i could use this piece of code to show/hide layers of certain class?
February 28th, 2007 at 10:53
I was putting together an eBay ad that needed this script (great script by the way!). Come to find out, eBay will not allow the replace() function. So I just removed the function, refactored slightly, and this is now working for me in my eBay ads (given there's no hyphens in the class names of course).
<code>
function mcsGetElementsByClassName(oElm, strTagName, oClassNames){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var arrRegExpClassNames = new Array();
var oClassNames2 = (typeof oClassNames == "object") ? oClassNames : [ oClassNames ];
for(var i=0; i
February 28th, 2007 at 10:55
try again…
<code>
function mcsGetElementsByClassName(oElm, strTagName, oClassNames){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var arrRegExpClassNames = new Array();
var oClassNames2 = (typeof oClassNames == "object") ? oClassNames : [ oClassNames ];
for(var i=0; i
February 28th, 2007 at 11:58
Simon, joncl,
I'm glad it was of use to you!
joncl,
You need to escape < with < and > with > to make it work.
March 5th, 2007 at 20:55
[...] liminate the library dependence. You do need a getClass and event handler function. I used getElementsByClassName by Robert Nyman and John Resig’s addevent [...]
March 7th, 2007 at 21:32
I have a rather strange question, one I hope will not offend you – do you know where your last name originated from? I am doing research into my family line and Nyman came up – could you help?
sorry to bother you
,but please answer – thanks
March 8th, 2007 at 0:10
[...] tsByClassName function. Luckily, though, I was spared that horrible fate, because I found the Ultimate getElementsByClassName, courtesy of a guy by the name of [...]
March 8th, 2007 at 0:51
[...] ling or tripling page load times in IE6. Workaround: Use an optimized version. cf. The ultimate getElementsByClassName Filed u [...]
March 8th, 2007 at 10:00
[...] de(); } } return outArray; } The Ultimate getElementsByClassName Uses a pure DOM implementation, t [...]
March 8th, 2007 at 11:07
Babette,
Ha ha, don't worry!
To be honest, I don't really know. Nyman literally means "new man" in Swedish (and I'm, naturally then, Swedish), but that's all I know about it.
March 9th, 2007 at 13:44
[...] = treeWalker.nextNode(); } } return outArray; } The Ultimate getElementsByClassName [url] function getElementsByClassName(oElm, strTagName, strClassN [...]
March 12th, 2007 at 16:10
[...] he link is clicked first gets some elements through a getElementsByClassname function (try The Ultimate getElementsByClassName or DOMAssistant’s core file [...]
March 16th, 2007 at 18:13
[...] cade-prosessin mukaisesti. Vinkki: luokkia voi käyttää tyylin määrittämisen lisäksi XHTML- ja HTML-elementtien käsittelyyn Javascriptillä. 8. Mozilla-sp [...]
March 19th, 2007 at 14:56
Thank for this great stuff which get my LiFE-LiNE project possible !
)
March 20th, 2007 at 16:52
[...] The Ultimate getElementsByClassName [...]
March 24th, 2007 at 1:59
Really great function !!
Could you clarify the licence (GPL, BSD, …) you're releasing it?
It could be strange to ask this, but I want to use it in GPL code and depending on the licence you've choosed it may be an issue (for me
).
Thanks
March 25th, 2007 at 20:23
murdos,
Acutally, no license and it’s free to use. If I had released it under a license, back in the day, it would have been the Creative Commons Attribution-ShareAlike 2.5 license.
May 11th, 2007 at 17:34
[...] a small note to those of you who use my getElementsByClassName script: it has been updated for performance reasons and flexibility [...]
May 12th, 2007 at 14:42
Nice one. Thanks for the code. I have actually used it a couple of times. Keep up the good work.
May 13th, 2007 at 23:29
James,
Nice, I'm glad that you like it!
May 14th, 2007 at 13:55
[...] qui va ré-afficher les blocs cachés. Ce qui est trés facile àfaire en utilisant la ressource getElementsByClassName* de Jonathan Snook et Robert Nyman… Ces blocs seront donc visibles seulement si le navigateur [...]
May 16th, 2007 at 10:49
Good Stuff. Pure Plug and Play!
Thanks!
May 16th, 2007 at 22:42
I've made a slight modification to your latest example that suports multiple class names, I had to search through elements that contained multiple class names but only select thoes that contain at least on the the class names I'm searching on. that may sound confusing but the solution I found is simply this:
for(var j=0; j<arrElements.length; j++){
oElement = arrElements[j];
bMatchesAll = false;
for(var k=0; k<arrRegExpClassNames.length; k++){
var classname = oElement.className.split(" ");
for(q=0;q<classname.length;q++){
if(arrRegExpClassNames[k].test(classname[q])){
bMatchesAll = true;
break;
}
}
}
if(bMatchesAll){
arrReturnElements.push(oElement);
}
}
May 16th, 2007 at 22:49
Enoch,
Thanks for sharing.
May 25th, 2007 at 7:17
Looks like you have the documentation on your function incorrect…the first attribute is the class, the second is the tag and the third is the document object
May 25th, 2007 at 12:37
Tad,
As is written at the top of the post, the updated version has a changed order for calling. You can choose to use ny of the old versions or the new one.
May 28th, 2007 at 20:35
[...] As a side note: I originally got parts of this code from Robert Nyman’s Ultimate getElementByClassName post. Filed under: JavaScriptBy Sid Roberts On May 28, 2007 At 6:24 pm Comments : [...]
June 18th, 2007 at 19:31
Hello,
I've wrote my own getElementsByClassName, and a can say it's the ultimate one. It support Browsers who come with native getElementsByClassName-support (already in Firefox3), and it uses FAST FAST FAST XPath to get the nodes.
You can find it here: <a> <a href="http://;http://phpfi.com/238008” target=”_blank”>;http://phpfi.com/238008
For some browsers (like Opera) you need also the following: <a> <a href="http://;http://phpfi.com/238014” target=”_blank”>;http://phpfi.com/238014
Thanks
July 3rd, 2007 at 14:09
[...] när sidan laddats. highslidealiceImages är en aningen omskriven och anpassad version av Robert Nymans utmärkta getElementsByClassName som ser till att alla bilder med klassen »highslide« initieras och blir klickbara. [...]
July 9th, 2007 at 22:57
[...] semplice e di banale utilizzo. Se le esigenze fossero diverse, Robert’s Talk, nel suo blog, ha raccolto tutta una serie di funzioni per ricavare gli elementi a partire dal nome [...]
August 5th, 2007 at 5:17
Hey, crash.
What would it take to make your code work in IE?
August 5th, 2007 at 5:29
Crash,
I thought EVALUATE was considered to be EVIL.
gfed
August 9th, 2007 at 11:17
gfed: You need indexOf for Arrays, see: http://phpfi.com/238014
document.evaluate() isn't eval() they doesn't do anything similar.
August 16th, 2007 at 17:21
[...] The Ultimate getElementsByClassName [...]
August 29th, 2007 at 21:32
I am having a problem with the function. When called within another function I get error:
elm.getElementsByTagName is not a function
and it points to this line:
var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
Any idea what is going on?
August 29th, 2007 at 21:36
Seth,
Depending on what version you use of the function (there are two), you shall either send in an object reference as the first parameter, or (optionally) send in an object reference as the third parmater (this goes for the revised version of the function, at the beginning of this post).
An object reference looks something like this:
<code>document.getElementById("container")</code>
August 29th, 2007 at 23:57
I called the function like this:
sum = getElementsByClassName(document, "input", "t_month");
Is the correct way to do it? I appriceate your quick response and general helpfulness!
August 30th, 2007 at 0:49
Nevermind, I got it! I was passing object and class backwards! Thank you again for your efforts toward writing this VERY helpful function! I wonder why it was overlooked when getElementById and TagName were conceived? Thank you, thank you, thank you!
August 30th, 2007 at 1:20
Seth,
Good that it worked out for you! I was a bit worried there for a while…
September 26th, 2007 at 21:04
Hi there!
I am glad to find the getElementsByClassName function – it's really helpful. Thank you for it!
But I have a question about regular expression which is used in both versions.
As I know regular expression lets you search a string for the first matching pattern and test(param) returns true if it finds the regular expression in param.
If so, why can't we just use testClass = new RegExp(strClassName)? When used with test(param), just like in your function, it would check for first match of strClassName in the object's className:
if(oRegExp.test(oElement.className)){
arrReturnElements.push(oElement);
}
Thank you for your answer!
September 26th, 2007 at 21:31
Ann,
Thank you! It's because other class names might contain the exact same text and more, and you don't want to match partial words. E.g. if you're looking for elements that have the class valid you don't want to match the term validation if some other class has that.
September 26th, 2007 at 21:51
Thank you for your answer!
I've just tried to understand it on my own and write that now I know
Once again thanks for great function
October 5th, 2007 at 6:05
This my version. Supports a negated className lookup.
//supports matching all classes other than the one passed like !myClassName
function getElementsByClassName(className, tag, elm){
var neg = '';
var testClass = null;
if(className.charAt(0) === '!'){
testClass = new RegExp('(^|s)(?'+className+')w+(s|$)')
className = className.substring(1,className.length);
} else {
testClass = new RegExp('(^|s)'+ className + '(s|$)');
}
var tag = tag || '*';
var elm = elm || document;
var elements = (tag == '*' && elm.all)? elm.all : elm.getElementsByTagName(tag);
var returnElements = [];
var current;
var length = elements.length;
for(var i=0; i < length; i++){
current = elements[i];
if(testClass.test(current.className)){
returnElements.push(current);
}
}
return returnElements;
}
October 5th, 2007 at 10:52
Chris,
Interesting approach with the negated className route!
October 15th, 2007 at 17:34
Hi, I think it's imperative to have an optional call back here! What's the typical usage of this function? to retrieve an array of elements and then do something to them. So you've just gone through a for() loop to get the array and now you have to go through another loop to do whatever it was you wanted to do.
So it would be something like this:
<code>
function getElementsByClassName(className, tag, elm, callBack){
var testClass = new RegExp("(^|\s)" + className + "(\s|$)");
var tag = tag || "*";
var elm = elm || document;
var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
var returnElements = [];
var current;
var length = elements.length;
for(var i=0; i<length; i++){
current = elements[i];
if(testClass.test(current.className)){
if(callBack)callBack(current);
returnElements[returnElements.length]=current;
//returnElements.push(current);
}
}
return returnElements;
}
</code>
also I've done a little timing test and appending items to an array using .length is a little bit faster (in FF)
October 31st, 2007 at 21:49
[...] CSS class, however. To help with this, I found a nice JavaScript function called getElementsByClassName() by Jonathan Snook and Robert Nyman. Calling this function placed all the DIV objects with the [...]
November 1st, 2007 at 2:32
Hi everyone. Sorry for the long comment. This getElementsByClassName script is great, but it just doesn't seem to be recognized by Blogger. I only know a little JS, so I need some help. Here's the code. Explanation follows.
<code>
var draftOn=true;
var draftClass=document.getElementsByClassName(document.getElementById("main"), "span", "draft");
function hideShowDraft(){
if(draftOn==true){
draftClass.style.display="none";
draftOn=false;
} else if(draftOn==false){
draftClass.style.display="inline";
draftOn=true;
}
}
</code>
I'm trying to make a function where I can hide and show text that's put in <code><span class="draft"></code>. I have a text anchor <code><a onclick="hideShowDraft();">Hide/Show<a></code> that when clicked changes the CSS of all the <code>span</code> tags with the class <code>"draft"</code>.
I'm doing this in Blogger, so I don't know if it's a template problem or what. I put the script tag <code><script language="text/javscript" src="blah/blah/getElementsByClassName.js"> </script></code> in the <code>head</code> tag, and I know that I linked the script right because it's in the same folder as my other scripts. Spelling's right and everything.
I know I wrote the function right because I tested it by making the background image to none: <code>document.body.style.backgroundImage="none";</code> when I click on it. I just can't seem to get <code>getElementsByClassName</code> to work. I couldn't get <code>getElementsByTagName</code> to work either when I was just targeting the <code>span</code> tag. Can anyone figure out what the problem is? Thank you so much!
November 1st, 2007 at 13:48
Ivan,
First, you need to find all the elements with the class
draftclass after the HTML elements are in place. This can, for example, be done by inserting your code after all the HTML or by using awindow.onloadevent. Plese read more about this in AJAX, JavaScript and accessibility.Then, in the function
hideShowDraftyou need to loop through all the elements in the variabledraftClass, since it is anarrayof elements. Like this:function hideShowDraft(){
for(var i=0; i<draftClass.length; i++){
if(draftOn==true){
draftClass[i].style.display=”none”;
draftOn=false;
} else if(draftOn==false){
draftClass[i].style.display=”inline”;
draftOn=true;
}
}
}
November 1st, 2007 at 22:59
Thank you so much, Robert! I really appreciate you helping me out. Keep up the good work!
November 2nd, 2007 at 14:47
Ivan,
No problem Good luck!
November 6th, 2007 at 9:54
I was using this one for Firefox-specific greasemonkey scripts. I just did some profiling, and I should have used XPATH.
<code>
function $x(p, context) {
if (!context) context = document;
var i, arr = [], xpr = document.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (i = 0; item = xpr.snapshotItem(i); i++) arr.push(item);
return arr;
}
$x("//a[contains(@class,'current')]");
</code>
November 8th, 2007 at 13:53
Should downloadable file include both old and revised versions of the function(s) ?
November 8th, 2007 at 16:59
engtech,
Yes, for Firefox, XPath is much faster.
Chris,
Yes, it contains all version. Then choose the one you seem fit and implement it where you want to use it.
November 9th, 2007 at 0:42
Thank you, ths is by far the best explanation and script i have found around, this saved me so much time.
Thanks again …
November 9th, 2007 at 13:04
Coder,
Thank you!
November 26th, 2007 at 21:02
[...] world who have already noticed this, so there are many already written. I use Robert Nyman’s getElementsByClassName [...]
December 14th, 2007 at 17:48
THANK YOU!!!!
December 14th, 2007 at 23:19
Shannon,
You're welcome.
December 22nd, 2007 at 9:35
[...] kaut gan kas t?ds pras?s ?oti bieži. Tikai daž?di Javascript veid?gi risin?jumi k? The Ultimate getElementsByClassName vai ar? daž?die freimworki, kas pied?v? l?dz?gu [...]
January 4th, 2008 at 9:02
Wired. This Function comes pretty bloated. Multiple classNames, callback functions and tagName parameter. So much work for a simple function? Native getElementsByClassName don't have those parameters.
I've wrote my own speeed version above, to just to have one (be cause some ppl ask for). I write JavaScript all day, I know my DOM and never had a use for such a function.
January 4th, 2008 at 22:46
Crash,
So, you have never had any use for such a method? Interesting. How do you implement your solutions in an accessible and unobtrusive manner? To me, there's no better way to select out any number of elements where <code>id</code> won't be sufficient, rather than by their class name.
Multiple class names is in a separate version and not needed. Not sure what you mean with a callback function. <code>tagName</code> is there to optimize performance, something which is not needed in the same way when it is implemented natively.
January 8th, 2008 at 12:22
Here's my own version of a Javascript getElementsByClassName, it adds the function prototype to the Object class, giving it the same functionality as getElementById and getElementsByTagName
Usage:
document.getElementsByClassName('myClass'); // returns array of all elements of class 'myClass'
or
document.getElementById('myId').getElementsByClassName('myClass'); // returns array of all elements of class 'myClass' who's parentNode has the id 'myId'
or even
document.getElementsByClassName('myClass')[0].getElementsByClassName('anotherClass'); // returns array of all elements of class 'anotherClass' who's parentNode is the first element in the document of class 'myClass'
Object.prototype.getElementsByClassName = function(clsName) {
var retVal = new Array();
var elements = this.getElementsByTagName('*');
for (var i=0; i= 0) {
var classes = elements[i].className.split(' ');
for (var j=0; j<classes.length; j++) {
if (classes[j] == clsName)
retVal.push(elements[i]);
}
}else if (elements[i].className == clsName)
retVal.push(elements[i]);
}
return retVal;
}
January 8th, 2008 at 12:40
Lisa,
Yes, I've seen that approach before, but i prefer having just one loop and using regular expressions, instead of crating new arrays all the time with split.
Also, it is never good practice to attach something to the core Object in JavaScript, so I'd recommend adding it to the HTML elements themselves in the web page.
January 12th, 2008 at 2:18
[...] that the above JS code depends on Robert Nyman’s ultimate getElementsByClassName implementation and the Prototype JavaScript framework. filed in Internet/technology () tagged with ie7, [...]
January 21st, 2008 at 22:37
Hi.
I didn't like the way this function had to be called, I found it too un-intuitive. Mostly when I need a function like this, I need it short and simple. Also, I didn't like to pass an object to the function for all the classes I needed – too complicated, I wanted to have it as flexible as in html's class="" itself.
Now I don't know whether it is bad for the overall performance when you add functions to the Node prototype itself, but that's what I just did: Now you can call the function on any node to get elements of given classnames inside of it. Of course you can use it on the document node itself too, to get all matching elements in the whole documnt.
Maybe this is a good place to get some profound answers to the performance question – Does one have to be careful with Node-prototype-functions regarding the performance of the site/document??
However, here are some examples of how to call the version changed by me:
<code>
var e = document.getElementsByClassName('green')[0];
var form = document.getElementsByClassName('floating login box', 'form');
var form = document.getElementsByClassName('login box floating', 'form');
/* if you need only elements within a specific element: */
var container = document.getElementById('container');
var boxes = container.getElementsByClassName('box');
/* handy: */
var boxes = $('container').getElementsByClassName('box');
</code>
So here is the changed version:
<code>Node.prototype.getElementsByClassName = function () {
/*
Written by Jonathan Snook, http://www.snook.ca/jonathan
Add-ons by Robert Nyman, http://www.robertnyman.com
and Jovica Aleksik, loopmode@loopmode.de
arguments: className, [tagName]
*/
if (this.nodeType != 9) {
return;
}
var oElm = this;
var oClassNames = arguments[0].indexOf(' ') != -1 ? arguments[0].split(' ') : arguments[0];
var strTagName = arguments[1] ? arguments[1] : '*';
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var arrRegExpClassNames = new Array();
if(typeof oClassNames == "object"){
for(var i=0; i<oClassNames.length; i++){
arrRegExpClassNames.push(new RegExp("(^|s)" + oClassNames[i].replace(/-/g, "-") + "(s|$)"));
}
}
else{
arrRegExpClassNames.push(new RegExp("(^|s)" + oClassNames.replace(/-/g, "-") + "(s|$)"));
}
var oElement;
var bMatchesAll;
for(var j=0; j<arrElements.length; j++){
oElement = arrElements[j];
bMatchesAll = true;
for(var k=0; k<arrRegExpClassNames.length; k++){
if(!arrRegExpClassNames[k].test(oElement.className)){
bMatchesAll = false;
break;
}
}
if(bMatchesAll){
arrReturnElements.push(oElement);
}
}
return (arrReturnElements)
};
</code>
January 21st, 2008 at 22:41
Shame on me, didn't even look at previous comments…and missed object-prototype version above
Quite similar, though I allowed for space-separated, multiple classnames in addition.
Heh..
So what about performance issues – no matter at all?
Possible/hypothetical differences between object and Node prototype?
January 22nd, 2008 at 12:13
Jovica,
I have no information about performance, but it seems a bit superfluous to add the method to every element in the web page. When it comes to calling the method on an element itself, though, I agree that it is a nicer approach.
My suggestion is to only add the method to elements that need it, and it's the base approach of my DOMAssistant library.
February 4th, 2008 at 15:18
[...] un JavaScript busca todos esos spans (el c?digo para seleccionar los spans de una cierta clase ni siquiera es m?o) y le a?ade el punteado, la mosca y el enlace. Con la gracia que si dese?ramos cambiar de buscador, [...]
February 14th, 2008 at 5:16
[...] Usually JavaScript libraries include a getElementsByClassName function. However, if you’re building your own personal library, you may want to include your own version. Robert Nyman has built and amended over the past 2.5 years a function for this very method: The Ultimate getElementsByClassName! [...]
March 6th, 2008 at 3:38
[...] I was able to quickly find Robert Nyman’s elegant getElementsByClassName function in The Ultimate GetElementsByClassName. [...]
April 7th, 2008 at 15:22
[...] make this bookmarklet I used some code from this site, and this little tool helped me out to compress the code. Posted inProjects, SoftwareApril 7th, [...]
April 11th, 2008 at 9:19
[...] as well. I would keep it in your arsenal if I were you. Furthermore, I am also borrowing the getElementsByClassName script from Robert Nyman. This will allow us to apply our javascript dynamically to our clock [...]
April 13th, 2008 at 14:50
[...] The Ultimate getElementsByClassName – A simple JS function to get elements by classname. Needed it to get my bookmarklet to work. [...]
April 27th, 2008 at 12:57
[...] The Ultimate getElementsByClassName http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsby… [...]
May 5th, 2008 at 14:34
Very good and usefull, thanks
May 27th, 2008 at 1:42
I couldn't get this working at first – turns out the code you have on this page has superfluos slashes in the regular expression. Copied and pasted from the JS file instead and that version was fine.
May 27th, 2008 at 2:03
website design,
Glad you like it!
Seb,
Ah, it was due to trying to prevent some WordPress escaping. The code in the post is ok now too.
May 27th, 2008 at 15:41
[...] and a half years ago, I released the first version of getElementsByClassName. With how web browsers has evolved since, I thought I’d release a real ultimate version, [...]
June 15th, 2008 at 1:37
[...] based Component So I implemented a very simple Sys.Component JavaScript object that uses the getElementsByClassName function to pull out all of the input elements with the watermark CSS class applied to them. The [...]
June 15th, 2008 at 1:48
[...] to them. To fetch these elements I am using a helper function called getElementsByClassName (taken from here) that scans the panel to find all of the elements that have this maintain-scroll class applied to [...]
July 4th, 2008 at 16:18
[...] Robert Nyman publicó en 2005 un artÃculo en el que mostraba la “Ultimate getElementsByClassName“, una función desarrollada en Javascript que sin necesidad de usar ningún tipo de framework nos permite obtener todos los elementos de una misma clase pasada por parámetro. [...]
July 25th, 2008 at 18:54
The ultimate solution is to use mootools =) it's offer a similar solution =)
August 12th, 2008 at 10:00
[...] Nyman, no ano de 2005, publicou em seu blog um artigo entitulado “The Ultimate getElementsByClassName“, uma função desenvolvida em JavaScript, que sem a utilização de [...]
November 23rd, 2008 at 21:23
[...] world who have already noticed this, so there are many already written. I use Robert Nyman’s getElementsByClassName [...]
January 23rd, 2009 at 16:50
works awesome, thanks so much
January 23rd, 2009 at 18:01
Mark,
Great!
February 6th, 2009 at 8:21
It seems that there is a bug in your getElementsByClassName realization in IE6.
I've got an "ObjectType error" in IE6, after quick investigation I've found that IE 6 supports document.getElementsByClassName but doesn't support elm.getElementsByClassName (where elm!=document).
So, the fix was very simple, on line 6:
<code>
- if (document.getElementsByClassName) {
+ elm = elm || document;
+ if (elm.getElementsByClassName) {
</code>
February 6th, 2009 at 9:41
Dmitry,
Thanks, but IE 6 does not support <code>document.getElementsByClassName</code>. In that case, you have something in your test page causing such a behavior.
February 9th, 2009 at 10:50
Hmm, very strange…
I have no any JS-frameworks on my page which can cause such a behavior in IE6.
But this issue is reproduced in some Opera versions, particulary in 9.26
Anyway, thanks for the getElementsByClassName
February 18th, 2009 at 11:55
hi,
i've wrote an getElementsByClassName too.
Are there any improvement suggestions?
you can call it these ways:
var myObj = document.getElementsByClassName(['foo', 'bar'], 'a');
var myObj = document.getElementsByClassName(['foo', 'bar']);
var myObj = document.getElementsByClassName('foo', 'a');
var myObj = document.getElementsByClassName('foo');
document.getElementsByClassName = function(cl,elem){
var elementsByClassName = [];
var regExpString = '';
if(typeof(elem) == 'undefined') elem = '*';
if(typeof(cl) == 'object'){
var countOfCl = cl.length;
var OR = "|";
for(var k=0; k < cl.length; k++){
countOfCl–;
if(countOfCl == 0) OR = '';
regExpString += 'b'+cl[k]+'b'+OR;
}
}else{
regExpString = 'b'+cl+'b';
}
var regExpString = new RegExp(regExpString);
var elements = this.getElementsByTagName(elem);
for (var i = 0; i < elements.length; i++) {
var className = elements[i].className;
if (regExpString.test(className)) elementsByClassName.push(elements[i]);
}
return elementsByClassName;
};
Greetings from Berlin
toni
February 18th, 2009 at 12:02
toniL,
My initial feedback would be that you shouldn't overwrite the native <code>document.getElementsByClassName</code> in web browsers if it already exists, but rather utilize it.
April 24th, 2009 at 19:02
I am not sure what I am doing wrong here, but what I am trying to do is to is to detect a browser and version (which I can do) and then switch off and on between the two spans.
var myBrowserVersion;
myBrowserVersion = parseInt(BrowserDetect.version);
//Detect if visitor is using Firefox 2 (less that version 3)
//If so just use a mailto method to send email.
//Otherwise use the abuse form
if (BrowserDetect.browser == "Firefox"){
//BrowserDetect.browser == "Firefox" && myBrowserVersion < 3
var badBrowser = getElementsByClassName("bad-Browser");
for(i = 0; i < badBrowser.length; i++) {
badBrowser.style.display = "none";
goodBrowser.style.display = "block";
}
}else {
var goodBrowser = getElementsByClassName("good-Browser");
for(i = 0; i < goodBrowser.length; i++) {
badBrowser.style.display = "block";
goodBrowser.style.display = "none";
}
}
<a>Report abuse
<a href="showdiv('comment${comment.commentID}Menu');" rel="nofollow">Report Abuse
April 24th, 2009 at 19:03
The editor cut this part off (I think)
<a>Report abuse
<a href="showdiv('comment${comment.commentID}Menu');" rel="nofollow">Report Abuse
April 24th, 2009 at 19:06
< span class="abuse bad-Browser" style="display: none;"> onething
< span class="abuse good-Browser" style="display: block;"> another thing
This is part of the span code I want to alternately show/ hide.
Sorry about not paying attention to the HTML instructions
April 24th, 2009 at 19:22
Tony,
Start by using the new version, linked to at the top of this page. If it fails, please provide a URL to a test page.
June 13th, 2009 at 7:57
[...] getElementsByClassName [...]
October 31st, 2009 at 1:49
Looking at the getelementsbyclassname again it looks like it is adding a class name to the id attribute. I don't know if that means I don't have to add the class= to the html or not? I have the 'a' tag writen as…
id="removeitem" class="removeitem"????????????
November 1st, 2009 at 2:15
Sorry I can't add/attach events to 'a' link in Table Row Table 'cell' to delete the row onclick with getelementbyclassname in IE. My guess is that IE dose not allow the class refrence to affect the table. Without the ability to do so I remain dumbfounded. I also assume that because the ultimate can't access the 'a' in an IE table row 'cell', it falls short of ultimate and unobtrusive javascript has a while to go??????
November 1st, 2009 at 3:30
Heinz,
This function does not add anything to an element, it's just a way to select them.
About your problems with IE: my guess is that you have called the function through <code>document.getElementsByClassName</code>, and not <code>getElemenetsByClassName</code>, so you don't get any references back to the element.
If you have a URL to a sample, please add it here.
November 2nd, 2009 at 11:08
Great function!
Thanks.
(Made by a Swede, naturally
)
November 2nd, 2009 at 12:47
Yngve,
Thanks!
November 5th, 2009 at 19:40
THANKS ROBERT I'LL TRY IT AGAIN TODAY. I'M ALSO GUESSING THAT OEL
IS CLASHING WITH EL IN MY ADDEVENT HANDLER. I'M HAVING A HARD TIME WITH POSTING SCRIPT WITH & LT FOR ETC.
November 5th, 2009 at 20:05
SORRY I GET THE BUTTON ELEMENTS WITH GETELEMENTS BY CLASS
USING ***VAR BUTTON=GET*** WITHOUT DOCUMENT?
THEN USE THE ADD EVENT TO ADD THE EVENT TO THE BUTTON. ONLY THING IS THAT THE GET USES OEL FOR ELEMENT? AND THE ADD USES EL?
November 5th, 2009 at 21:20
Heinz,
I really can't say why the rest of your code doesn't work, especially not when I can't see it. This function works to select elements with a certain class.
To be able to even have a chance to say what's wrong, you need to post a URL to where I can see your code in action.
November 5th, 2009 at 22:11
I JUST TRIED POSTING THE SCRIPT AGAIN USING
SCRIPT
BUT I DON'T SEE IT POSTED. MY SITE IS STILL IN MY DOCUMENTS FOLDER.
November 5th, 2009 at 22:23
<< for
function getElementsByClassName(oElm, strTagName, strClassName){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
strClassName = strClassName.replace(/-/g, "-");
var oRegExp = new RegExp("(^|s)" + strClassName + "(s|$)");
var oElement;
for(var i=0; i.
November 6th, 2009 at 0:01
HAY I USED & L T AT THE BEGINING OF EVERY LINE OF SCRIPT AND & G T AT THE END OF EVERY LINE BUT IT DOESN'T LOOK LIKE THE POST MADE IT.
November 6th, 2009 at 0:05
THE ONE THAT DID ONLY SHOWS HALF? I PUT & L T ; AT THE BEGINING OF THE SCRIPT AND & G T ; AT THE END?
November 9th, 2009 at 0:49
Heinz,
You need to escape the script properly to post it in a comment (although a public URL where it can be viewwd is much more preferable).
Either way, you should really be using a later version of the script.
March 21st, 2010 at 6:36
Nice method! Does anyone know how to get elements with classname1 OR classname2. I know I could use the third parameter as "["classname1", "classname2"]". But that includes only elements with both classnames. I would like to include elements that have or both or one of the specefied names.
March 22nd, 2010 at 12:16
ralph,
It's an interesting approach, but not supported by this function. I guess your best bet is one of the major JavaScript libraries, and then combine CSS selectors and check if one of them finds any matches.
August 19th, 2010 at 14:41
With all the references out there about document.getElementsByClassName, I thought today's browsers supported it but was obviously wrong. Seemed like such an obvious function to have.
Copied your function – worked a treat. Many thanks!
August 19th, 2010 at 21:19
Martin,
Thanks, glad you liked it!
March 3rd, 2011 at 11:32
my mistake. ofcourse tje document needs to be loaded first. shame on me.
March 3rd, 2011 at 12:22
does,
Glad it works!
March 24th, 2011 at 7:38
Nice,
Thanks! I think it will be helpful to my project.
August 2nd, 2011 at 18:12
why won’t this work? getElementsByClassName(document.getElementById(“left-nav”), “a”, “selected”).style.background=’#dee’;
thanks
August 2nd, 2011 at 18:53
luke,
Since the function returns an array of matching elements. If you only want to do something with the first match, you need to change it to this:
getElementsByClassName(document.getElementById(“left-nav”), “a”, “selected”)[0].style.background=’#dee’;
If you want to change all elements, you need to loop over all the matches, and change them one by one.
September 13th, 2011 at 8:41
I’m doing a thing of the identical interest and are taking note with this .Thanks.
November 26th, 2011 at 5:20
I am very grateful for this code. I had to resort to using getElementsByClassName as a work-around for an inability to load individual elements into an object array onload. Since my entire script depended on getElementsByClassName to compensate for this, I slammed my head through my desk when I found out it didn’t work in Internet Explorer 8. It’s near the end of 2011 and Microsoft still hasn’t figured out the basics of API, it’s time they just retire their project and leave it to the people who actually care about making progress in technology.
November 26th, 2011 at 9:39
John Schock,
Glad it was of use for you!
December 27th, 2011 at 2:52
[...] Nyman bereits vor einigen Jahren eine JScript-Bibliothek entwickelt (http://www.robertnyman.com, http://robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/), die die Suche nach HTML-Elemente einer gegebenen Klasse extrem [...]
August 21st, 2012 at 12:00
[...] known Jonathan Snook for many years, since the early days of my blogging, where we co-operated on a getElementsByClassName function. We’ve met in a number of places in the world, and now I’m happy to have [...]
Write a comment