Explain Codes LogoExplain Codes Logo

Find the closest ancestor element that has a specific class

javascript
dom-traversal
polyfill
event-delegation
Alex KataevbyAlex Kataev·Aug 31, 2024
TLDR

Spot the nearest ancestor with a designated class in a jiffy using the .closest() method in JavaScript:

let ancestor = element.closest('.my-class');

Just swap '.my-class' with the actual class you're tracking down, and element with the element starting your search. This clever snippet is widely accepted by modern browsers, so go ahead and give it a test run.

Polyfill approach: .closest() not available? No problem

Legacy browsers sometimes don't play nice with .closest(). Not to worry, a custom function with a while loop can come to your rescue. Here’s a workaround that uses element.parentElement to find your way around the DOM tree:

function findAncestor(el, cls) { while ((el = el.parentElement) && !el.classList.contains(cls)) { // Enjoying our trip up the tree? Hang on, this could get recursive. }; return el; // Found you, you rascal parent! }

To get this function running, call findAncestor(element, 'your-class') and replace 'your-class' with your class cipher, but don't forget to polyfill Element.matches() for the grey-bearded browsers out there.

Compatibility Gear Shift: When .matches() flexes its muscles

While .closest() remains a no-show, let‘s put .matches() to work, using parentElement as co-pilot:

function findAncestor(el, sel) { while (el && !(el.matches || el.matchesSelector).call(el, sel)) { el = el.parentElement; // Keep climbing, Jack and Jill! } return el; }

This function starts behaving like closest(), using selectors instead of just classes. Dust off your caniuse.com bookmark for a quick cross-browser check.

When trekking up the DOM, parentNode and parentElement may seem like twins, but notice this: parentElement returns Element nodes, while parentNode could return any node. If we're partying with class-related searches, better let parentElement lead the dance floor.

Minimize Overhead: Your Performance Versus Precision Trade-off

Looping through ancestor elements might feel like running uphill, so going native with .closest() is most efficient. Still, if you choose manual iteration, className.indexOf() might outpace classList.contains() in some browsers at the risk of precision.

Scenarios in real-world Applications

Stay on Top: Adapting to Dynamic Content

The DOM can morph in real time, with classes appearing and disappearing like magic, so keep your scripts flexible for "Now you see me, now you don't" scenarios. If required, poll the ancestors occasionally to keep up with the latest DOM story.

Event Handling and Propagation

Attaching an event listener at an ancestor level is a common practice. The .closest() method plays well with event delegation, pinpointing the event's ultimate target's ancestor like a pro.

Regular Expressions in Class Matching

If classes get funky names or split-personalities, regular expressions combined with manual DOM traversal can be your sherpa, checking for a pattern match in the class name.

References