Skip to content
Advertisement

Closest ancestor matching selector using native DOM?

Is anybody working on a jQuery.closest() equivalent in the DOM api?

Looks like the Selectors Level 2 draft adds matches() equivalent to jQuery.is(), so native closest should be much easier to write. Has adding closest() to Selectors come up?

Advertisement

Answer

See the element.closest() documentation.

Implementing such function with Element.matches() seems not optimal in terms of performance, cause apparently matches() will make a call to querySelectorAll() every time you test a parent, while only one call is sufficient for the job.

Here’s a polyfill for closest() on MDN. Note a single call to querySelectorAll()

if (window.Element && !Element.prototype.closest) {
  Element.prototype.closest = 
  function(s) {
      var matches = (this.document || this.ownerDocument).querySelectorAll(s),
          i,
          el = this;
      do {
          i = matches.length;
          while (--i >= 0 && matches.item(i) !== el) {};
      } while ((i < 0) && (el = el.parentElement)); 
      return el;
  };
}

But bear in mind that function implemented like this will not work properly on unattached tree (detached from document.documentElement root)

//Element.prototype.closestTest = function(s){...as seen above...};

var detachedRoot = document.createElement("footer");
var child = detachedRoot.appendChild(document.createElement("div"));
detachedRoot.parentElement; //null

child.closestTest("footer"); //null

document.documentElement.append(detachedRoot);
child.closestTest("footer"); //<footer>   

Though closest() that is implemented in Firefox 51.0.1 seems to work fine with detached tree

document.documentElement.removeChild(detachedRoot);
child.closestTest("footer"); //null
child.closest("footer"); //<footer>
8 People found this is helpful
Advertisement