Use the closest() method to get the closest parent element by class, e.g. child. closest('. parent') . The closest() method traverses the Element and its parents until it finds a node that matches the provided selector.
class selector selects elements with a specific class attribute. To select elements with a specific class, write a period (.) character, followed by the name of the class. You can also specify that only specific HTML elements should be affected by a class.
To select all ancestor elements of an element, the parents() method is used. This method is used to find all the parent elements related to the selected element. This method traverse all the levels up the selected element and return that all elements.
The closest() method searches up the DOM tree for elements which matches a specified CSS selector. The closest() method starts at the element itself, then the anchestors (parent, grandparent, ...) until a match is found. The closest() method returns null() if no match is found.
Update: Now supported in most major browsers
document.querySelector("p").closest(".near.ancestor")
Note that this can match selectors, not just classes
https://developer.mozilla.org/en-US/docs/Web/API/Element.closest
For legacy browsers that do not support closest()
but have matches()
one can build selector-matching similar to @rvighne's class matching:
function findAncestor (el, sel) {
while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
return el;
}
This does the trick:
function findAncestor (el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
The while loop waits until el
has the desired class, and it sets el
to el
's parent every iteration so in the end, you have the ancestor with that class or null
.
Here's a fiddle, if anyone wants to improve it. It won't work on old browsers (i.e. IE); see this compatibility table for classList. parentElement
is used here because parentNode
would involve more work to make sure that the node is an element.
Use element.closest()
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
See this example DOM:
<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>
This is how you would use element.closest:
var el = document.getElementById('div-03');
var r1 = el.closest("#div-02");
// returns the element with the id=div-02
var r2 = el.closest("div div");
// returns the closest ancestor which is a div in div, here is div-03 itself
var r3 = el.closest("article > div");
// returns the closest ancestor which is a div and has a parent article, here is div-01
var r4 = el.closest(":not(div)");
// returns the closest ancestor which is not a div, here is the outmost article
Based on the the8472 answer and https://developer.mozilla.org/en-US/docs/Web/API/Element/matches here is cross-platform 2017 solution:
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
function findAncestor(el, sel) {
if (typeof el.closest === 'function') {
return el.closest(sel) || null;
}
while (el) {
if (el.matches(sel)) {
return el;
}
el = el.parentElement;
}
return null;
}
@rvighne solution works well, but as identified in the comments ParentElement
and ClassList
both have compatibility issues. To make it more compatible, I have used:
function findAncestor (el, cls) {
while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
return el;
}
parentNode
property instead of the parentElement
propertyindexOf
method on the className
property instead of the contains
method on the classList
property.Of course, indexOf is simply looking for the presence of that string, it does not care if it is the whole string or not. So if you had another element with class 'ancestor-type' it would still return as having found 'ancestor', if this is a problem for you, perhaps you can use regexp to find an exact match.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With