Getting elements by class name

February 2, 2010

The topic of getting elements by their class name is one that has been covered by many people, but nothing seems to put together all of the information in such a way that it works across most of the web browsers out there.

Within the past couple of years, modern web browsers have added their own native getElementsByTagName that is incredibly fast, when compared with using a script. Other web browsers such as Internet Explorer do not have a native implementation, so still require a scripted solution for these other browsers. Here’s how to achieve that in a cross-browser manner.

Even though there are a wide variety of getElementsByTagName scripts that people have created, many of them only partially resolve the issle. Ultimately there are two major issues at hand:

  1. Detecting whether a browser already has a getElementsByTagName implementation
  2. Limit the search by tag name, to assist slower web browsers

The first issue is nicely resolved thanks to advice from Sid Robert’s blog

Due to a number of compatibility issues with different web browsers, we need to assign the script to both Object.prototype and document. As we don't want to overwrite the native implementation of getElementsByTagName, we'll use the || operator to attempt to assign the native implementation first so that if that fails, the anonymous function that follows it can be used instead.

Object.prototype.getElementsByClassName = document.getElementsByClassName =
    document.getElementsByClassName || function (searchClass, tag) {

John Resig has a getElementsByTagName Speed Comparison that lists many of the popular getElementsByTagName functions. For this post I have chosen to use the one by Dustin Diaz, which has the fastest DOM implementation. This function is compatible back to IE6. In order to be compatible with IE5 we would need to use a different technique to obtain all of the tags, as using '*' with getElementsByTagName fails to work in IE5.

A few updates have been made to this function so that things like unspecified arguments are correctly detected, and that issues that might be picked up by JSLint are tidied up.

This is the cross-browser compatibility script for getElementsByClassName

Object.prototype.getElementsByClassName = document.getElementsByClassName =
    document.getElementsByClassName || function (searchClass, tag) {
    if (tag === undefined) {
        tag = '*';
    }
    var classElements = [],
        els = this.getElementsByTagName(tag),
        elsLen = els.length,
        pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)"),
        i, j;
    for (i = 0, j = 0; i < elsLen; i += 1) {
        if (pattern.test(els[i].className)) {
            classElements[j] = els[i];
            j += 1;
        }
    }
    return classElements;
};

With the above script running before other code that uses el.getElementsByClassName, you can now safely ensure that your code will run successfully on a wide range of web browsers.