Check if an element contains a class in JavaScript?
Asked Answered
S

30

985

Using plain JavaScript (not jQuery), Is there any way to check if an element contains a class?

Currently, I'm doing this:

var test = document.getElementById("test");
var testClass = test.className;

switch (testClass) {
  case "class1":
    test.innerHTML = "I have class1";
    break;
  case "class2":
    test.innerHTML = "I have class2";
    break;
  case "class3":
    test.innerHTML = "I have class3";
    break;
  case "class4":
    test.innerHTML = "I have class4";
    break;
  default:
    test.innerHTML = "";
}
<div id="test" class="class1"></div>

The issue is that if I change the HTML to this...

<div id="test" class="class1 class5"></div>

...there's no longer an exact match, so I get the default output of nothing (""). But I still want the output to be I have class1 because the <div> still contains the .class1 class.

Sunroom answered 5/5, 2011 at 13:40 Comment(2)
element.classList.contains(cls)Voltmeter
document.getElementsByClassName('class1').lengthAllopath
B
1711

Use element.classList .contains method:

element.classList.contains(class);

This works on all current browsers and there are polyfills to support older browsers too.


Alternatively, if you work with older browsers and don't want to use polyfills to fix them, using indexOf is correct, but you have to tweak it a little:

function hasClass(element, className) {
    return (' ' + element.className + ' ').indexOf(' ' + className+ ' ') > -1;
}

Otherwise you will also get true if the class you are looking for is part of another class name.

DEMO

jQuery uses a similar (if not the same) method.


Applied to the example:

As this does not work together with the switch statement, you could achieve the same effect with this code:

var test = document.getElementById("test"),
    classes = ['class1', 'class2', 'class3', 'class4'];

test.innerHTML = "";

for(var i = 0, j = classes.length; i < j; i++) {
    if(hasClass(test, classes[i])) {
        test.innerHTML = "I have " + classes[i];
        break;
    }
}

It's also less redundant ;)

Backbencher answered 5/5, 2011 at 13:46 Comment(17)
Awesome, but how do I use that in combination with the switch statement so that I can change the output based on which classes the div contains?Sunroom
@daGUY: What do you want to do with the switch statement anyway? E.g. The second div has two classes but it would only output I have class1 as you are using break. If you want to output every class an element has, then you can just take the className and split it on white spaces. Or what is your actual goal?Backbencher
@Felix Kling: I need the innerHTML of the div to change between four different strings depending on which class it contains. I just used "I have class1", etc. as examples - the real strings are all different. I will only be showing one string at a time, not combining any (hence the breaks after each case). I just want it to still work even if the matching class is one of multiple classes on the div.Sunroom
@Felix Kling: that did it, thanks so much! I'm actually not outputting the names of the classes, but rather one of four entirely different strings, so I modified it slightly with a few IF/ELSE IF statements to handle each one. Works perfectly though.Sunroom
@daGUY: You're welcome. You could get rid of the if/else statements, if you just create another array of messages where the index of the message is the same as the index of the class... just a suggestion ;)Backbencher
@Felix Kling: I'll try that, thanks for the suggestion! My JS skills are not up to the level of my HTML/CSS skills... :-)Sunroom
@Felix Kling: one question...at the end of the first line of your updated code, you have a comma instead of a semi-colon - does that declare "classes" as a variable as well without you having to retype "var"? I noticed that the code still works even with a semi-colon instead of the comma; just wondering what the difference is.Sunroom
@daGUY: Exactly. You can use one var like this if you separate the variable declarations with a comma. But you should put a semicolon at the end of the last declaration. This is often done to make a block of variable declarations more apparent.Backbencher
FYI: for svg elements, in browsers such as a safari, className is not a string but an object of type svganimatedstring. Checking the class attribute rather than className is currently the most cross-browser way to check class if you are working with svg elements.Stuckup
A neat trick with switch statements which will work nicely here is to turn the logic around: switch (true) { case hasClass(element,'class1'): ... break; case hasClass(element,'class2'): ... break; }Lacewing
classList is a good call. Just to follow up on the excellent info already provided, unfortunately it looks like classList is waiting on IE10. Just when you thought IE9 was good enough to call a "modern browser", you're back to polyfilling here (which MDN helpfully provides for IE8 & 9)Hetrick
Is there a specific reason why you added spaces before and after?Buchmanism
@Ced: this is so that searching for foo wouldn't match foobar.Backbencher
Why is there a space before and after element.className?Singlet
@KayceBasques: because we also add spaces to cls so that we only match full class names. hasClass(element, 'foo') should not match for class foobar. And if we didn't add spaces to element.className we could never match the first or last class names.Backbencher
Ah, I see. If the element's classes were foo bar and you tested for ` bar ` (since spaces were added) then it wouldn't match. So you add the spaces so that the element's classes become ` foo bar `... ThanksSinglet
classList() works but it returns the Array of classnames by using split(" "). So for example the element has class attribute as <i class='fa fa-cube fa-lg, liTmptCuboid, dldCuboidButton' title='Template Cuboid'></i>, The list contents 1. fa 2. fa-cube 3. fa-lg, 4. liTmptCuboid, 5. dldCuboidButton In this case I used the classList as follows: if(ev.target.classList.contains("fa-cube")) AND IT WORKED. WHERE AS following classList FAILS. if(ev.target.classList.contains("fa fa-cube fa-lg")). CHECKING CODE IN DEBUGGER WINDOW CLARIFIES THIS.Saphena
S
133

The easy and effective solution is trying .contains method.

test.classList.contains(testClass);
Selfrenunciation answered 28/5, 2015 at 13:14 Comment(0)
A
99

In modern browsers, you can just use the contains method of Element.classList :

testElement.classList.contains(className)

Demo

var testElement = document.getElementById('test');

console.log({
    'main' : testElement.classList.contains('main'),
    'cont' : testElement.classList.contains('cont'),
    'content' : testElement.classList.contains('content'),
    'main-cont' : testElement.classList.contains('main-cont'),
    'main-content' : testElement.classList.contains('main-content'),
    'main main-content' : testElement.classList.contains('main main-content')
});
<div id="test" class="main main-content content"></div>

Supported browsers

enter image description here

(from CanIUse.com)


Polyfill

If you want to use Element.classList but you also want to support older browsers, consider using this polyfill by Eli Grey.

Adornment answered 20/1, 2016 at 20:54 Comment(0)
U
20

This question is pretty solidly answered by element.classList.contains(), but people got pretty extravagant with their answers and made some bold claims, so I ran a benchmark.

Remember that each test is doing 1000 iterations, so most of these are still very fast. Unless you rely extensively on this for a specific operation, you won't see a performance difference.

I ran some tests with basically every way to do this. On my machine, (Win 10, 24gb, i7-8700), classList.contains performed super well. So did className.split(' ') which is effectively the same.

The winner though is classList.contains(). If you're not checking for classList to be undefined, ~(' ' + v.className + ' ').indexOf(' ' + classToFind + ' ') creeps ahead 5-15%

enter image description here

Uzzia answered 16/6, 2021 at 0:54 Comment(0)
S
16

Element.matches()

element.matches(selectorString)

According to MDN Web Docs:

The Element.matches() method returns true if the element would be selected by the specified selector string; otherwise, returns false.

Therefore, you can use Element.matches() to determine if an element contains a class.

const element = document.querySelector('#example');

console.log(element.matches('.foo')); // true
<div id="example" class="foo bar"></div>

View Browser Compatibility

Stripy answered 8/11, 2018 at 3:56 Comment(2)
Seems cleaner and less cumbersome to me, though I'm curious how this compares in terms of performance.Gurgitation
@Gurgitation .matches is 3-4x slower. jsben.ch/iKweEUzzia
W
11

Since he wants to use switch(), I'm surprised no one has put this forth yet:

var test = document.getElementById("test");
var testClasses = test.className.split(" ");
test.innerHTML = "";
for(var i=0; i<testClasses.length; i++) {
    switch(testClasses[i]) {
        case "class1": test.innerHTML += "I have class1<br/>"; break;
        case "class2": test.innerHTML += "I have class2<br/>"; break;
        case "class3": test.innerHTML += "I have class3<br/>"; break;
        case "class4": test.innerHTML += "I have class4<br/>"; break;
        default: test.innerHTML += "(unknown class:" + testClasses[i] + ")<br/>";
    }
}
Whilst answered 17/5, 2012 at 21:33 Comment(1)
I was just wondering the same thing, but yes, that's the closest to the original problem!Hotbed
M
7

Here is a little snippet If you’re trying to check wether element contains a class, without using jQuery.

function hasClass(element, className) {
    return element.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(element.className);
}

This accounts for the fact that element might contain multiple class names separated by space.

OR


You can also assign this function to element prototype.

Element.prototype.hasClass = function(className) {
    return this.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(this.className);
};

And trigger it like this (very similar to jQuery’s .hasClass() function):

document.getElementById('MyDiv').hasClass('active');
Machismo answered 28/5, 2015 at 9:13 Comment(1)
I prefer this solution more. It avoids the issue of the class name partially matching another class and doesn't require polyfills to work in IE.Sidestep
U
6

A simplified oneliner:1

function hasClassName(classname,id) {
 return  String ( ( document.getElementById(id)||{} ) .className )
         .split(/\s/)
         .indexOf(classname) >= 0;
}

1 indexOf for arrays is not supported by IE (ofcourse). There are plenty of monkey patches to be found on the net for that.

Uncommitted answered 5/5, 2011 at 14:31 Comment(0)
A
6

This is a little old, but maybe someone will find my solution helpfull:

// Fix IE's indexOf Array
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement) {
        if (this == null) throw new TypeError();
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) return -1;
        var n = 0;
        if (arguments.length > 0) {
            n = Number(arguments[1]);
            if (n != n) n = 0;
            else if (n != 0 && n != Infinity && n != -Infinity) n = (n > 0 || -1) * Math.floor(Math.abs(n));
        }
        if (n >= len) return -1;
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) if (k in t && t[k] === searchElement) return k;
        return -1;
    }
}
// add hasClass support
if (!Element.prototype.hasClass) {
    Element.prototype.hasClass = function (classname) {
        if (this == null) throw new TypeError();
        return this.className.split(' ').indexOf(classname) === -1 ? false : true;
    }
}
Aristaeus answered 28/6, 2012 at 12:12 Comment(6)
use: 'element.hasClass('classname');Aristaeus
Why did you use t.length >>> 0 ? As far as I know it is a noop if you use '0', right?Assume
wow so much code for something simple. Why not use a regular expression and not reinvent the wheel? you could just use /^class_name_you_are_searching_for$/.test(myElement.className)Suetonius
I wrote that too fast. Just to not overcomplicate my regular expression it would be /\s*class_name_you_are_searching_for\s*/.test(myElement.className)Suetonius
@Suetonius - i write my own libraries for future use. and this just adds to my stack. of course other solutions would work, this is just my prefered wayAristaeus
@Dementic very true. To each their own. Anybody coming to this page cannot say they don't have choices :)Suetonius
C
5

className is just a string so you can use the regular indexOf function to see if the list of classes contains another string.

Caterwaul answered 5/5, 2011 at 13:43 Comment(4)
What about testing for class class in the above example?Backbencher
From experience, this method can be quite risky: It will return true when you look for the class foo on an element which has the foobar class.Blitzkrieg
Sure, you just have be aware of what you are testing. Felix's code works well by using spaces as the delimiter.Caterwaul
Fails to account for nested instances of a class name. Example: 'end' can be found in the class name 'frontend'.Damascene
F
5

I know there a lot of answers but most of these are for additional functions and additional classes. This is the one I personally use; much cleaner and much less lines of code!

if( document.body.className.match('category-page') ) { 
  console.log('yes');
}
Forehand answered 21/12, 2015 at 7:58 Comment(2)
this method may return false positives when searching for a class name that partially matches - e.g.<body class="category-page"> and document.body.className.match('page') - will match but there is no class page attached to the elementSeumas
Can be resolved with \b, e.g. /\bpage\b/g, since it's regex (note: have to use / /g).Lobule
M
4

To check if an element contains a class, you use the contains() method of the classList property of the element:*

element.classList.contains(className);

*Suppose you have the following element:

<div class="secondary info">Item</div>*

To check if the element contains the secondary class, you use the following code:

 const div = document.querySelector('div');
 div.classList.contains('secondary'); // true

The following returns false because the element doesn’t have the class error:

 const div = document.querySelector('div');
 div.classList.contains('error'); // false
Minicam answered 11/1, 2021 at 12:8 Comment(0)
P
3

I've created a prototype method which uses classList, if possible, else resorts to indexOf:

Element.prototype.hasClass = Element.prototype.hasClass || 
  function(classArr){
    var hasClass = 0,
        className = this.getAttribute('class');
  
    if( this == null || !classArr || !className ) return false;
  
    if( !(classArr instanceof Array) )
      classArr = classArr.split(' ');

    for( var i in classArr )
      // this.classList.contains(classArr[i]) // for modern browsers
      if( className.split(classArr[i]).length > 1 )  
          hasClass++;

    return hasClass == classArr.length;
};


///////////////////////////////
// TESTS (see browser's console when inspecting the output)

var elm1 = document.querySelector('p');
var elm2 = document.querySelector('b');
var elm3 = elm1.firstChild; // textNode
var elm4 = document.querySelector('text'); // SVG text

console.log( elm1, ' has class "a": ', elm1.hasClass('a') );
console.log( elm1, ' has class "b": ', elm1.hasClass('b') );
console.log( elm1, ' has class "c": ', elm1.hasClass('c') );
console.log( elm1, ' has class "d": ', elm1.hasClass('d') );
console.log( elm1, ' has class "a c": ', elm1.hasClass('a c') );
console.log( elm1, ' has class "a d": ', elm1.hasClass('a d') );
console.log( elm1, ' has class "": ', elm1.hasClass('') );

console.log( elm2, ' has class "a": ', elm2.hasClass('a') );

// console.log( elm3, ' has class "a": ', elm3.hasClass('a') );

console.log( elm4, ' has class "a": ', elm4.hasClass('a') );
<p class='a b c'>This is a <b>test</b> string</p>
<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="50px">
    <text x="10" y="20" class='a'>SVG Text Example</text>
</svg>

Test page

Punt answered 14/10, 2014 at 13:48 Comment(2)
Is there a reason why you'd want to use classlist instead of index of e.className? Seems like the perf are less goodBuchmanism
@Buchmanism - well, perf is irrelevant if you're not testing thousands of elements for their class, (it will probably be refactored in browsers in the future). it's more elegant to use because the code describes its functionality, but bottom line, it doesn't matter, do whatever you want :)Punt
P
2

Here's a case-insensitive trivial solution:

function hasClass(element, classNameToTestFor) {
    var classNames = element.className.split(' ');
    for (var i = 0; i < classNames.length; i++) {
        if (classNames[i].toLowerCase() == classNameToTestFor.toLowerCase()) {
            return true;
        }
    }
    return false;
}
Penzance answered 5/5, 2011 at 13:57 Comment(0)
X
2
  1. Felix's trick of adding spaces to flank the className and the string you're searching for is the right approach to determining whether the elements has the class or not.

  2. To have different behaviour according to the class, you may use function references, or functions, within a map:

    function fn1(element){ /* code for element with class1 */ }
    
    function fn2(element){ /* code for element with class2 */ }
    
    function fn2(element){ /* code for element with class3 */ }
    
    var fns={'class1': fn1, 'class2': fn2, 'class3': fn3};
    
    for(var i in fns) {
        if(hasClass(test, i)) {
            fns[i](test);
        }
    }
    
    • for(var i in fns) iterates through the keys within the fns map.
    • Having no break after fnsi allows the code to be executed whenever there is a match - so that if the element has, f.i., class1 and class2, both fn1 and fn2 will be executed.
    • The advantage of this approach is that the code to execute for each class is arbitrary, like the one in the switch statement; in your example all the cases performed a similar operation, but tomorrow you may need to do different things for each.
    • You may simulate the default case by having a status variable telling whether a match was found in the loop or not.
Xebec answered 5/5, 2011 at 16:40 Comment(0)
A
2

I would Poly fill the classList functionality and use the new syntax. This way newer browser will use the new implementation (which is much faster) and only old browsers will take the performance hit from the code.

https://github.com/remy/polyfills/blob/master/classList.js

Aikoail answered 15/1, 2014 at 19:5 Comment(0)
M
2

If the element only has one class name you can quickly check it by getting the class attribute. The other answers are much more robust but this certainly has it's use cases.

if ( element.getAttribute('class') === 'classname' ) {

}
Midwife answered 17/1, 2015 at 20:31 Comment(0)
P
2

See this Codepen link for faster and easy way of checking an element if it has a specific class using vanilla JavaScript~!

hasClass (Vanilla JS)

function hasClass(element, cls) {
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
Psychosomatic answered 2/10, 2017 at 3:58 Comment(0)
E
2

This is supported on IE8+.

First we check if classList exists if it does we can use the contains method which is supported by IE10+. If we are on IE9 or 8 it falls back to using a regex, which is not as efficient but is a concise polyfill.

if (el.classList) {
  el.classList.contains(className);
} else {
  new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}

Alternatively if you are compiling with babel you can simply use: el.classList.contains(className);

Egotist answered 24/7, 2018 at 0:41 Comment(0)
C
1

I think that perfect solution will be this

if ($(this).hasClass("your_Class")) 
    alert("positive");            
else              
    alert("Negative");
Corpulent answered 6/1, 2014 at 9:17 Comment(2)
1. "Using plain JavaScript (not jQuery)" 2. Use bracketsConakry
3 - use ParenthesisForehand
D
1

This is a bit off, but if you have an event that triggers switch, you can do without classes:

<div id="classOne1"></div>
<div id="classOne2"></div>
<div id="classTwo3"></div>

You can do

$('body').click( function() {

    switch ( this.id.replace(/[0-9]/g, '') ) {
        case 'classOne': this.innerHTML = "I have classOne"; break;
        case 'classTwo': this.innerHTML = "I have classTwo"; break;
        default: this.innerHTML = "";
    }

});

.replace(/[0-9]/g, '') removes digits from id.

It is a bit hacky, but works for long switches without extra functions or loops

Disembowel answered 19/7, 2017 at 9:58 Comment(0)
W
0

Try this one:

document.getElementsByClassName = function(cl) {
   var retnode = [];
   var myclass = new RegExp('\\b'+cl+'\\b');
   var elem = this.getElementsByTagName('*');
   for (var i = 0; i < elem.length; i++) {
       var classes = elem[i].className;
       if (myclass.test(classes)) retnode.push(elem[i]);
   }
    return retnode;
};
Wylma answered 5/5, 2011 at 13:48 Comment(2)
Be careful with the word boundary. It will also match true if you have e.g. a class foo-bar and search for foo.Backbencher
Hi Jimy, so I was searching for this \b metacharacter and it only considers [a-zA-Z0-9_] as word characters. So for a classnames containing a minus char this won't work.Chacha
A
0

in which element is currently the class '.bar' ? Here is another solution but it's up to you.

var reg = /Image/g, // regexp for an image element
query = document.querySelector('.bar'); // returns [object HTMLImageElement]
query += this.toString(); // turns object into a string

if (query.match(reg)) { // checks if it matches
  alert('the class .bar is attached to the following Element:\n' + query);
}

jsfiddle demo

Of course this is only a lookup for 1 simple element <img>(/Image/g) but you can put all in an array like <li> is /LI/g, <ul> = /UL/g etc.

Algarroba answered 5/7, 2016 at 21:5 Comment(0)
M
0

Just to add to the answer for people trying to find class names within inline SVG elements.

Change the hasCLass() function to:

function hasClass(element, cls) {
    return (' ' + element.getAttribute('class') + ' ').indexOf(' ' + cls + ' ') > -1;
  }

Instead of using the className property you'll need to use the getAttribute() method to grab the class name.

Molder answered 25/7, 2018 at 18:51 Comment(0)
L
0

I created these functions for my website, I use only vanilla javascript, maybe it will help someone. First I created a function to get any HTML element:

//return an HTML element by ID, class or tag name
    var getElement = function(selector) {
        var elements = [];
        if(selector[0] == '#') {
            elements.push(document.getElementById(selector.substring(1, selector.length)));
        } else if(selector[0] == '.') {
            elements = document.getElementsByClassName(selector.substring(1, selector.length));
        } else {
            elements = document.getElementsByTagName(selector);
        }
        return elements;
    }

Then the function that recieve the class to remove and the selector of the element:

var hasClass = function(selector, _class) {
        var elements = getElement(selector);
        var contains = false;
        for (let index = 0; index < elements.length; index++) {
            const curElement = elements[index];
            if(curElement.classList.contains(_class)) {
                contains = true;
                break;
            }
        }
        return contains;
    }

Now you can use it like this:

hasClass('body', 'gray')
hasClass('#like', 'green')
hasClass('.button', 'active')

Hope it will help.

Landel answered 27/11, 2019 at 8:51 Comment(0)
P
0

Tip: Try to remove dependencies of jQuery in your projects as much as you can - VanillaJS.

document.firstElementChild returns <html> tag then the classList attribute returns all classes added to it.

if(document.firstElementChild.classList.contains("your-class")){
    // <html> has 'your-class'
} else {
    // <html> doesn't have 'your-class'
}
Peggiepeggir answered 13/2, 2020 at 8:54 Comment(0)
H
0

Since .className is a string, you can use the string includes() method to check if your .className includes your class name:

element.className.includes("class1")
Hachmann answered 25/7, 2020 at 15:57 Comment(0)
F
0

Using the classList is also ideal

HTML

<div id="box" class="myClass"></div>

JavaScript

const element = document.querySelector("#box");

element.classList.contains("myClass");
Forever answered 9/10, 2020 at 10:31 Comment(0)
W
0

As the accepted answer suggests, Element.className returns a string, so you can easily check if a class exists by using the indexOf() method:

element.className.indexOf('animated') > -1

If you are interested in the performance difference between indexOf vs classList.contains, using indexOf seems to be slightly faster. I did a quick benchmark performance test to check that. Here are my findings: ClassName.indexOf vs ClassList.contains.

Waive answered 10/2, 2021 at 20:25 Comment(0)
U
-1

For me the most elegant and faster way to achieve it is:

function hasClass(el, cl) {
        return el.classList ? el.classList.contains(cl) : !!el.className && !!el.className.match(new RegExp('(?: |^)' + cl + '(?: |$)'));
    }

enter image description here

Urmia answered 30/5, 2018 at 12:22 Comment(4)
First, that regex isn't totally reliable, or efficient. The (capturing group) is unnecessary. You should use (?: |^)c'+i+'(?: |$). Second, this is far from the fastest. jsben.ch/QAOQsUzzia
@RegularJo I run your test, but it results to me that regex is the fastestUrmia
@RegularJo also the "c" in your regex is wrong, the correct regex is '(?: |^)'+i+'(?: |$)'Urmia
Lol, yep, forgot to update my regex from the test to change the c back.Uzzia

© 2022 - 2024 — McMap. All rights reserved.