70

I want to check if a class exsits somewhere in one of the parent elements of an element.

I don't want to use any library, just vanilla JS.

In the examples below it should return true if the element in question resides somewhere in the childs of an element with "the-class" as the class name.

I think it would be something like this with jQuery:

if( $('#the-element').parents().hasClass('the-class') ) { return true; } 

So this returns true:

<div> <div class="the-class"> <div id="the-element"></div> </div> </div> 

So does this:

<div class="the-class"> <div> <div id="the-element"></div> </div> </div> 

...but this returns false:

<div> <div class="the-class"> </div> <div id="the-element"></div> </div> 
3
  • 4
    Using jquery this would be with closest('.theclass').length Commented May 31, 2013 at 18:51
  • Do you have any code to show what you have tried so we can see where you may need assistance with? Commented May 31, 2013 at 18:53
  • So, you want to see if any of the ancestors, or siblings of ancestors, have a given class-name? Commented May 31, 2013 at 18:57

11 Answers 11

86

You can use the closest() method of Element that traverses parents (heading toward the document root) of the Element until it finds a node that matches the provided selectorString. Will return itself or the matching ancestor. If no such element exists, it returns null.

You can convert the returned value into boolean

const el = document.getElementById('div-03'); const r1 = el.closest("#div-02"); console.log(Boolean(r1)); // returns the element with the id=div-02 const r2 = el.closest("#div-not-exists"); console.log(Boolean(r2));
<article> <div id="div-01">Here is div-01 <div id="div-02">Here is div-02 <div id="div-03">Here is div-03</div> </div> </div> </article>

Sign up to request clarification or add additional context in comments.

6 Comments

This is the more modern answer. However, it has no support for an ancient browser called Internet Explorer, and would require a polyfill. (MDN Reference)
This is the answer you want unless you still have to support MSIE 11 or lesser.
This should be the accepted answer.
When looking for a class as a parent of a div using JQuery, I check for length 0 or 1 since Boolean always returns true. console.log(r1.length);
What a godsend of an answer.
|
63

You'll have to do it recursively :

// returns true if the element or one of its parents has the class classname function hasSomeParentTheClass(element, classname) { if (element.className.split(' ').indexOf(classname)>=0) return true; return element.parentNode && hasSomeParentTheClass(element.parentNode, classname); } 

Demonstration (open the console to see true)

12 Comments

this fails if som parent doesnt have a class
cannot split of undefined
I used this code to work with elements with no class: var hasSomeParentTheClass = function(element, classname) { if (element.className && element.className.split(' ').indexOf(classname) >= 0) return true; return element.parentNode && hasSomeParentTheClass(element.parentNode, classname); }
Using parentElement instead of parentNode will avoid this problem.
@lexa IE9 has no idea what a classList is.
|
13

You can use some and contains to achieve the result:

function hasParentWithMatchingSelector (target, selector) { return [...document.querySelectorAll(selector)].some(el => el !== target && el.contains(target) ) } // usage hasParentWithMatchingSelector(myElement, '.some-class-name'); 

1 Comment

This is really clever.. just needs a fix because el.contains(el) returns true. So we should rewrite it as: el !== target && el.contains(target)
8

The fiddle

The code

function hasClass(element, className) { var regex = new RegExp('\\b' + className + '\\b'); do { if (regex.exec(element.className)) { return true; } element = element.parentNode; } while (element); return false; } 

OR

function hasClass(element, className) { do { if (element.classList && element.classList.contains(className)) { return true; } element = element.parentNode; } while (element); return false; } 

Comments

5

I'm ok with the function that Denys Séguret posted, it looks elegant and I like it. I just tweaked a little bit that function since if the class specified in the parameter, is not present in the whole DOM, it fails when the recursion reaches the document object because is true that we control if the element has the parent node (in the last line, and when the document is the element the parent node is null) but before we execute the previous line, and when the element is the document, document.className is undefined and it fails, so the control must be moved to the top.

function hasSomeParentTheClass(element, classname) { // // If we are here we didn't find the searched class in any parents node // if (!element.parentNode) return false; // // If the current node has the class return true, otherwise we will search // it in the parent node // if (element.className.split(' ').indexOf(classname)>=0) return true; return hasSomeParentTheClass(element.parentNode, classname); } 

1 Comment

there isn't a need for a separate conditional, you can do it by doing an explicit null check to make sure you get a boolean: element.parentNode != null && hasSomeParentTheClass(..)
3

I believe if( $('#the-element').parents('.the-class').length ) to be more efficient, but perhaps not as human-readable; which, with querySelector in the picture, could be replaced with the following method:

function hasParent(element, parentSelector) { var potentialParents = document.querySelectorAll(parentSelector); for(i in potentialParents) if(potentialParents[i].contains(element)) return potentialParents[i]; return false; } 

That'd give you the ability to do:

var elm = document.getElementById('the-element'); if(hasParent(elm, '.the-class')) return true; 

4 Comments

I had the same problem and I came up with this solution, so I thought I'd post it here for others facing this issue.
why is $ more efficent?
@SuperUberDuper I was not suggesting that jQuery is more efficient than single purposed vanilla code, if that's what you're asking. I was implying, I think, that using a selector with parents may result in one less loop, compared to OP's jq line. Bad phrasing, huh?
This is a great method. I only suggest running a .hasOwnProperty() check.
3

Try the closest() function - For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. Refer to the Official Docs here.

Comments

2

Another alternative for some those who like this style for modern/polyfilled browsers.

const hasClass = (element, className) => { return element.classList.contains(className); }; const hasParent = (element, className) => { if (!element.parentNode) { return false; } if (hasClass(element, className)) { return true; } return hasParent(element.parentNode, className) }; 

Working demo:

const hasClass = (element, className) => { return element.classList.contains(className); }; const hasParent = (element, className) => { if (!element.parentNode) { return false; } if (hasClass(element, className)) { return true; } return hasParent(element.parentNode, className) }; /* Demo Code, can ignore */ const child = document.getElementById('child'); const orphan = document.getElementById('orphan'); const output = document.getElementById('output'); const log = `child has parent? ${hasParent(child, 'list')} orphan has parent? ${hasParent(orphan, 'list')} ` output.innerText = log;
#output { margin-top: 50px; background: black; color: red; padding: 20px; }
<div> <ul class="list"> <li> <a id="child" href="#">i have a parent</a> </li> </ul> </div> <div> <ul> <li> <a id="orphan" href="#">im an orphan</a> </li> </ul> </div> <div id="output"></div>

Comments

1

My example for Vanilla JS, it's use a vanilla equivalent of parents() from jQuery

var htmlElement = <htmlElement>, parents = [], classExist; while (htmlElement = htmlElement.parentNode.closest(<parentSelector>)) { parents.push(htmlElement); } classExist = (parents > 0); 

So your selector just to be a .className

And just check if parent is > 0

Comments

0

My solution: (it goes up to html element)

// e = element // name = name of class // Returns element or undefined function classParent( e, name ) { if( e.parentElement ) if( e.parentElement.classList.contains( name )) return e.parentElement; else return classParent( e.parentElement, name ) } 

Comments

-1

Because ID must be unique on document context, you could just use instead:

return !!document.querySelector('.the-class #the-element'); 

If you want to include element itself, you can use:

return !!document.querySelector('.the-class #the-element, #the-element.the-class'); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.