The Ultimate getElementsByClassName

Published on Monday, November 7th, 2005

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

Posted in JavaScript | 206 comments

206 comments

  • Rowan Lewis
    November 7th, 2005 at 11:33

    Nice! Support for IE5 is more than I’d have ever asked for :)

    BTW, The design rocks :)

  • Jorkas
    November 7th, 2005 at 11:53

    Looks nice Robert, of course i will try it out!

    // Jorkas

  • Kimmo. » Webin videopalveluita
    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 [...]

  • amix
    November 7th, 2005 at 14: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 ;)

  • Zilla Smash! » Blog Archive » This looks useful
    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� [.]

  • Curtis Harvey
    November 7th, 2005 at 20:21

    Instead of escaping the hyphen couldn’t you use the RegExp "(^| )"+strClassName+"( |$)"?

    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.

  • andr3
    November 7th, 2005 at 20: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)

  • Anne van Kesteren
    November 7th, 2005 at 20:30

    Does this take multiple class names into account? (See the getElementsByClassName definition in HTML 5.) If not, not sure if this is the ultimate solution ;-)

  • Robert Nyman - author
    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:

    Our current test platforms include all of the modern and poular browsers: Safari 2.0.1, Firefox 1.0.7, Firefox 1.5b2, and Internet Explorer 6

    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!

    couldn’t you use the RegExp "(^| )"+strClassName+"( |$)"?

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

  • Curtis Harvey
    November 7th, 2005 at 21:02

    I tried that, but for some reason it didn’t work (although it should). Another way of putting it is “(^|\s)”+ etc.

    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

  • Robert Nyman - author
    November 7th, 2005 at 21:32

    Curtis,

    Hmm… I have used that regexp in my own version of getElementsByClassName for a while now and haven’t run into any problems.

    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:

    getElementsByClassName(document, "a", "info-links left"); will match <a class="info-links left">A tag</a>, but it won’t match <a class="left info-links">A tag</a>.

    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.

  • Anne van Kesteren
    November 7th, 2005 at 23: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 className DOM attribute. I only took a brief look at the code so therefore I asked.

  • Robert Nyman - author
    November 7th, 2005 at 23: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… :-)

  • Curtis Harvey
    November 8th, 2005 at 3: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.

  • Curtis Harvey
    November 8th, 2005 at 3: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.

  • Robert Nyman - author
    November 8th, 2005 at 9: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!

  • Bruce Weirdan
    November 8th, 2005 at 11:33

    Yes, I don’t know why it didn’t work in my testing. Weird. But the word boundaries work!

    Regexp with word boundaries will match ‘info-links-big’ while searching for ‘info-links’ (hyphen is considered as word boundary), while it shouldn’t.

  • Robert Nyman - author
    November 8th, 2005 at 13:21

    Bruce,

    Thank you for that invaluable feedback!
    The scripts and the post are now changed to using "(^|\\s)" and "(\\s|$)" 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.

  • Curtis
    November 8th, 2005 at 18: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 breaking 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.

  • Curtis
    November 8th, 2005 at 18: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.

  • Robert Nyman - author
    November 8th, 2005 at 20:14

    Curtis,

    It’s ok. :-)

    since you are no longer using word boundaries, why escape the hyphens?

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

    once one RegExp match fails there is no reason to check the remaining, so breaking out of the loop might save a wee-bit of time.

    I was apparently sloppy; of course there should be a break; statement there. It’s added in the code and post now.

    …but I just like the syntactic sugar of passing a space delimited string…

    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.

    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?

    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?

  • Curtis
    November 8th, 2005 at 21:03

    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?

    Shouldn’t it be getElementsByClassName.js instead of getElementsByTagName.js? ;)

    It’s totally ok with your comments, I really like this constructive discussion!

    Good, me too.

  • Curtis
    November 8th, 2005 at 21:43

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

    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:
    * getElementsByClassName(document, '.+-.+'); would match any element belonging to any hyphenated class.
    * getElementsByClassName(document, "b{3}.*"); 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.

  • Robert Nyman - author
    November 8th, 2005 at 22:04

    Curtis,

    Shouldn’t it be getElementsByClassName.js instead of getElementsByTagName.js? ;)

    Ha ha! That is freaky!
    Force of habit, I guess… :-)

    …by not escaping hyphens–or any special characters–you could use a regular expression pattern for the classname.

    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! :-)

  • andr3
    November 9th, 2005 at 14:25

    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.

  • Robert Nyman - author
    November 9th, 2005 at 14:34

    andr3,

    Thank you, I’m happy to hear that! :-)

  • Steve Williams
    November 9th, 2005 at 23:14

    Does it come with an ‘update available’ link included :)

  • Robert Nyman - author
    November 10th, 2005 at 9: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… :-)

  • Sri’s Blog » links for 2005-11-09
    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 [...]

  • Adam van den Hoven
    November 10th, 2005 at 22: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:


    document.getElementById("SomeElement").getElementsByClassName( "div", "someclass" )

    Now, that would be cool.

  • Robert Nyman - author
    November 11th, 2005 at 16:39

    Adam,

    From the top of my head, you can use this in Mozilla web browsers:


    HTMLElement.prototype.getElementsByClassName = function (strTagName, strClassName) {
    getElementsByClassName(this, strTagName, strClassName);
    };

    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.

  • John
    November 13th, 2005 at 14:46

    Instead of using "(^|\\s)" + strClassName + "(\\s|$)" might I suggest "\b" + strClassName + "\b".

  • Robert Nyman - author
    November 13th, 2005 at 21: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.

  • otro blog m�s » Unos cuantos de desarrollo web (LXV)
    November 19th, 2005 at 17:38

    [...] ma entrega… Comenzamos con cosas de Javascript y DOM… En Robert’s Talk, una funci�n ge [...]

  • Ed
    November 19th, 2005 at 22: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?

  • Ed
    November 23rd, 2005 at 18: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

  • Robert Nyman - author
    November 23rd, 2005 at 19: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 &lt; and > with &gt;.

  • Ed
    November 23rd, 2005 at 20:42

    oh, sorry about the code!

    You can see how I’m using it at
    this sample page.

  • Ed
    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.

  • Robert Nyman - author
    November 23rd, 2005 at 21:10

    Ed,

    No problem. :-)
    And sure, splitting class names can also be an approach.

  • lamberete
    November 28th, 2005 at 17: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 ;)

  • Robert Nyman - author
    November 28th, 2005 at 17:45

    lamberete,

    Thanks! :-)

  • christian
    December 12th, 2005 at 9:19

    What is the difference/advantage of this method over something like Simon Willison’s getElementBySelector?

  • Robert Nyman - author
    December 12th, 2005 at 9: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.

  • christian
    December 13th, 2005 at 8: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. :)

  • Robert Nyman - author
    December 13th, 2005 at 9:44

    christin,

    Absolutely, I agree. The power of specificity should definitely not be underrated. :-)

  • louis w
    December 28th, 2005 at 23:18

    how can i override the prototype version of this with yours?

  • Robert Nyman - author
    December 29th, 2005 at 10: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 getElementsByClassName function within the prototype JavaScript file.

  • Chuck Bradley
    January 21st, 2006 at 15:21

    louis w,

    In prototype, getElementsByClassName 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:
    getElementsByClassName(document, '*', 'foo');
    document.getElementsByClassName('foo');

  • Robert Nyman - author
    January 23rd, 2006 at 9:21

    Chuck,

    Yes, I believe those two will be the same.

  • Robert’s talk » How to get a good search engine ranking
    January 24th, 2006 at 23:19

    getElementsByClassName [...]

  • Notes pour (beaucoup) plus tard » Du JavaScript…
    January 29th, 2006 at 18:45

    [...] commentaire » Un Back to top. » The Ultimate getElementsByClassName.   Catégories: java [...]

  • Henrik
    February 4th, 2006 at 17:23

    Congratz Robert :) You’re on stylegala in the news section!

  • Robert Nyman - author
    February 4th, 2006 at 21: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.

  • Klient » Blog Arkiv » Ännu en Image Replacement teknik
    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 [...]

  • Dustin Diaz
    February 6th, 2006 at 20: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 :)

  • Robert Nyman - author
    February 6th, 2006 at 22:03

    Dustin,

    Ah, right, it seems to be popular! :-)

  • David
    February 18th, 2006 at 23:51

    You should add support for Moz’s XPath which will greatly speed things up.

  • Robert Nyman - author
    February 20th, 2006 at 9: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. :-)

  • Micah Goulart
    February 22nd, 2006 at 19:26

    One system we’ve setup is using CSS selectors, such as

    getElementsByClassName(”div.myclass”)

  • Robert Nyman - author
    February 23rd, 2006 at 10: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.

  • Diego
    March 21st, 2006 at 23: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?

  • Robert Nyman - author
    March 22nd, 2006 at 8:53

    Diego,

    Thank you! :-)

    why you didn’t use the Element.all property to speed up search in case of IE?

    You mean instead of getElementsByTagName? I wanted to use standard DOM methods as far as possible, and I haven’t experienced any performance lack because of that.

  • Jimmy
    March 23rd, 2006 at 3: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!

  • Robert Nyman - author
    March 23rd, 2006 at 8:54

    Jimmy,

    No problem, I’m glad it helped! :-)

  • Robert’s talk » AJAX, JavaScript and accessibility
    March 23rd, 2006 at 14:38

    [...]getElementsByClassName [...]

  • fadtastic - a multi-author web design trends journal » Blog Archive » Robert Nyman, Jonathan Snook and Dustin Diaz - a triple interview
    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 [...]

  • Nate Cavanaugh
    March 29th, 2006 at 23: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 :)

  • Robert Nyman - author
    March 30th, 2006 at 9: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.

  • l0b0
    March 30th, 2006 at 9: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?

  • Robert Nyman - author
    March 30th, 2006 at 9:59

    l0b0,

    I just took a very quick glance at the code but didn’t directly see why it didn’t work. getElementsByClassName just returns an array of elements, so the problem seems to lie in your toggle function.

    What if you made the array helpElements into a global variable and then referenced it?

  • l0b0
    March 30th, 2006 at 14: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.

  • Robert Nyman - author
    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 array directly; loop throgh it and just alert what you have in every position and you will see it.

  • Adam Messinger
    April 9th, 2006 at 2: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.

  • Robert Nyman - author
    April 9th, 2006 at 19:18

    Adam,

    Thanks! :-)
    The credit comment is all it takes, no license. Go crazy with it!:-)

  • Adam Messinger
    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 of moo.dom.js + prototype.lite.js is 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.

  • Robert Nyman - author
    April 15th, 2006 at 20:13

    Adam,

    Thanks for the tip!

  • gorbiz
    April 17th, 2006 at 22:18

    I love it!
    I almost always write my code myself, thou this can not be improved and should not be modified. (:

    Thanks!

  • Robert Nyman - author
    April 18th, 2006 at 8:48

    gorbiz,

    Thank you! :-)

  • getElementsByClassName Deluxe Edition | Muffin Research Labs
    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 [...]

  • aNieto2K | Lo que quiero, cuando quiero y como quiero » getElementBy…
    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 [...]

  • webdesign zoic.be » Zoic Archive » Robert Nyman, Jonathan Snook and Dustin Diaz - a triple interview
    May 13th, 2006 at 13:50

    [...] ’s version and then shaped by valuable feedback from talented people (please see the [...]

  • Michael Winter
    May 16th, 2006 at 12: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,

    Array.prototype.push = ArrayPush;
    function ArrayPush(value){
      this[this.length] = value;
    }

    should be replaced with:

    Array.prototype.push = function(value){
      this[this.length] = value;
    };

    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:

    if (typeof Array.prototype.push != 'function') {
      Array.prototype.push = function(value){
        this[this.length] = value;
      }
    }

    Better still (in my opinion):

    if (typeof Array.prototype.push != 'function') {
      Array.prototype.push = function(v) {
        var i = this.length >>> 0,
            j = 0;
    i

        while(j

    The latter behaves exactly as described in section 15.4.4.7 of ECMA-262, 3rd Ed.

    Mike

  • Michael Winter
    May 16th, 2006 at 13:03

    Oops. Let’s try that again.

    if (typeof Array.prototype.push != 'function') {
      Array.prototype.push = function(v) {
        var i = this.length >>> 0,
            j = 0;

        while(j < arguments.length) {this[i++] = arguments[j++];}
        return this.length = i;
      };
    }

    Apologies,
    Mike

  • André Cassal
    May 25th, 2006 at 14:59

    function getElementsByClassName( _tag, _class, _scope){
    var regexp, classes, elements, element, returnElements;

    _scope = _scope || document;

    elements = !_tag || _tag == "*" ? document.all : _scope.getElementsByTagName(_tag);
    returnElements = [];

    classes = _class.split(/\s+/)
    regexp = new RegExp("(^|\\s+)("+ classes.join("|") +")(\\s+|$)","i")

    if(_class){
    for(var i=0; element = elements[i]; i++){
    if(regexp.test(element.className)){
    returnElements.push(element);
    }
    }
    return returnElements;
    }else{
    return elements;
    }
    }

    Usage:
    var inps = document.getElementsByClassName(”div”, “menu menu-top”, $(”menu”))

  • goetsu
    July 19th, 2006 at 23:39

    anybody use this script with opera 9 ? for me it doesn’t work.

  • wilfred nas
    July 21st, 2006 at 12:24

    Robert (or as you are on leave, Anyone),

    a co-worker spotted a possible mistake. We think that

    var arrElements = (strTagName == "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);

    Should be:

    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);

    As that it should only search in the original context, not the whole document..

    just our four (2×2) cents

    Wilfred and Sander

  • pike
    July 24th, 2006 at 13: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 ;-)

  • Robert Nyman - author
    July 24th, 2006 at 13: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 document.all 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:

    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.

  • Robert Nyman - author
    August 1st, 2006 at 20: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!

  • Robert Nyman - author
    August 1st, 2006 at 22:18

    Chi-Wai Lau,

    You need to escape HTML characters, i.e. &lt; 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:

    ["col", "left"]

  • Robert Nyman - author
    August 1st, 2006 at 22: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.

  • Robert Nyman - author
    August 1st, 2006 at 23: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).

  • dontcom.com - Personal website of Darren Wood » Blog Archive » links for 2006-08-21
    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[...]

  • Better Javascript : Mo Jebus
    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 [...]

  • Sander Bol
    September 25th, 2006 at 11:57

    Rovert,

    Thanks for putting this online - saved me a bunch of headaches and time. Clean, simple and efficient. Hurray for sharing.

    –S.B.

  • Sander Bol
    September 25th, 2006 at 11: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.

  • Robert Nyman - author
    September 25th, 2006 at 13:10

    Sander,

    I’m glad it helped. And don’t worry about the spelling… :-)

  • Vlad Fratila
    October 3rd, 2006 at 20:27

    Thank you for this, its support on IE is really great!

  • Robert Nyman - author
    October 3rd, 2006 at 21:40

    Vlad,

    No problem, I’m happy you like it. :-)

  • Matt Alexander
    October 16th, 2006 at 23: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.

  • Robert Nyman - author
    October 17th, 2006 at 8: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.

  • Particletree » JavaScript Basics for Prototyping
    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 [...]

  • Particletree » JavaScript Basics for Prototyping
    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 [...]

  • EJ - The only JavaScript library you’ll ever need - Robert’s talk
    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 [...]

  • Andy
    November 14th, 2006 at 23:38

    How about adding wildcard support to the class names ?

  • Robert Nyman - author
    November 15th, 2006 at 8: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.

  • Andy
    November 20th, 2006 at 20:47

    Yeah well, I discovered that it worked fine using regex statements so that’s alright.

  • Robert Nyman - author
    November 21st, 2006 at 8:42

    Andy,

    Ah, good.

  • JS, just it : Parte 2 - Implementando o getElementsByClassName » Angeruzzi.com
    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 [...]

  • Simz
    November 28th, 2006 at 16: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

  • Kenneth
    November 28th, 2006 at 18:55

    Couldn’t get it to work when using arrays. Wrote this for-loop instead:


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

  • Robert Nyman - author
    November 28th, 2006 at 21:14

    Simz,

    In the end of the post, there’s code for implementing support for push in IE 5.

  • Dennis
    December 18th, 2006 at 20:07

    worked great! thanks!

  • Soylent
    January 25th, 2007 at 21:43

    you could also use "\b"+strClassName+"\b" for the regular expression

    \b (bareword) will match word boundaries as well as the beginning/end

    reference

  • Soylent
    January 25th, 2007 at 22:46

    Sorry, make that: "\\b"+strClassName+"\\b"

  • Robert Nyman - author
    January 25th, 2007 at 22:50

    Soylent,

    As mentioned at the top of the article, word boundaries won’t work when there are hyphens in a className.

  • Soylent
    January 25th, 2007 at 22:51

    Okay, this thing is killing my double backslashes. So, that should be 2 backslashes before the b.

  • John Resig - getElementsByClassName in Firefox 3
    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 [...]

  • Firefox 3, integrará getElementByClassName | aNieto2K
    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 [...]

  • Broken Links » Blog Archive » Good news on FF3 and IE.next
    February 5th, 2007 at 0:33

    [...] entsByClassName. Fingers crossed the other browsers follow suit soon, so we can stop using 20 li [...]

  • Simon
    February 10th, 2007 at 19:07

    Robert,
    a very useful bit of code - thanks to it, I’ve managed to put together a method of expanding elements vertically.

    Thanks!

  • illimar
    February 23rd, 2007 at 10:32

    does anyone know how i could use this piece of code to show/hide layers of certain class?

  • joncl
    February 28th, 2007 at 8: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).


    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

  • joncl
    February 28th, 2007 at 8:55

    try again…

    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

  • Robert Nyman - author
    February 28th, 2007 at 9:58

    Simon, joncl,

    I’m glad it was of use to you!

    joncl,

    You need to escape < with &lt; and > with &gt; to make it work.

  • Daily misery » Blog Archive » Input mask revisit
    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 [...]

  • Babette