getElementsByClassName() with two classes

JavascriptHtmlDom

Javascript Problem Overview


Is it possible to get all elements with class a or b using getElementsByClassName() only once? I'd prefer vanilla JavaScript.

Javascript Solutions


Solution 1 - Javascript

You can't do it with getElementsByClassName() method instead use querySelectorAll() method with comma separated class selectors.

document.querySelectorAll('.a,.b')

Solution 2 - Javascript

You can pass more than one class name to getElementsByClassName() by separating them with spaces:

var elems = document.getElementsByClassName("class1 class2 class3");

Now, this differs from the .querySelectorAll(".class1,.class2,.class3") approach in that it applies a conjunction, not a disjunction — "and" instead of "or". Thus

var elems = document.getElementsByClassName("class1 class2 class3");

is like

var elems = document.querySelectorAll(".class1.class2.class3");

Sometimes you want one, sometimes you want the other. It's definitely true that .querySelectorAll() gives you much more flexibility.

Solution 3 - Javascript

No, you can't achieve that with only one document.getElementsByClassName() call. That function returns elements which have all of the classes specified in the first argument as a space-separated string.

There are two possible solution. First is to use document.querySelectorAll() instead, which uses CSS selectors.

document.querySelectorAll(".a, .b")

The second solution is to call document.getElementsByClassName() twice, turn the results into arrays using Array.from() and merge them using Array.prototype.concat(). To avoid duplicates (for example when element has both a and b class), you have to create a new Set from that array, and then turn it back to array using Array.from().

const classA = Array.from(document.getElementsByClassName("a"))
     ,classB = Array.from(document.getElementsByClassName("b"))
     ,result = Array.from(new Set(classA.concat(classB)))

See demo below:

console.log("first solution", document.querySelectorAll(".a, .b"))

const classA = Array.from(document.getElementsByClassName("a"))
     ,classB = Array.from(document.getElementsByClassName("b"))
     ,result = Array.from(new Set(classA.concat(classB)))

console.log("second solution", result)

<div class="a"></div>
<div class="b"></div>
<div class="a b"></div>
<div class="c"></div>

Note that the first solution gives an array-like NodeList object, whereas the second gives just an array.

Solution 4 - Javascript

Just to add a bit more support, here is a version that is compatible with older versions of IE and uses pure vanilla js :

function getElementsByClassNameOr(root, classNameString) // classNameString like '.a, .b' don't forget the comma separator
 {
    var arr = [],
    rx = new RegExp('(^|[ \n\r\t\f])' + classNameString + '([ \n\r\t\f]|$)'),
    elements = root.getElementsByTagName("*");
    
    var elem;

    for (i=0 ; i < elements.length ; i++) {
        elem = elements[i];
        if (rx.test(elem.className)) {
            arr.push(elem);
        }

    }

    return arr; // will contain all the elements that have one of the classes in ClassNameString, root can be document or a div.
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionUnknown developerView Question on Stackoverflow
Solution 1 - JavascriptPranav C BalanView Answer on Stackoverflow
Solution 2 - JavascriptPointyView Answer on Stackoverflow
Solution 3 - JavascriptMichał PerłakowskiView Answer on Stackoverflow
Solution 4 - Javascriptzoubida13View Answer on Stackoverflow