JSFiddle - React, Tailwind, and code Playground
HTML
<div id="foo">
<p>
<span>wrong</span>
<span class="hello" id="first">1</span>
<span class="hello">2</span>
</p>
<span id="correct">correct</span>
</div>
<div id='start'>
<div>
<div>
<span class='target'></span>
</div>
</div>
<div>
<span class='target' id="correct2"></span>
</div>
</div>
JavaScript
(function($) {
var matchesSelector = jQuery.find.matchesSelector;
$.fn.closestDescendant = function(selector) {
var queue, open, cur, ret = [];
this.each(function() {
queue = [this];
open = [];
while (queue.length) {
cur = queue.shift();
if (!cur || cur.nodeType !== 1) {
continue;
}
if (matchesSelector(cur, selector)) {
ret.push(cur);
return;
}
open.unshift.apply(open, $(cur).children().toArray());
if( !queue.length ) {
queue.unshift.apply( queue, open );
open = [];
}
}
});
ret = ret.length > 1 ? jQuery.unique(ret) : ret;
return this.pushStack(ret, "closestDescendant", selector);
};
})(jQuery);
console.assert( $("#foo").closestDescendant(".hello")[0] === $("#first")[0], "wrong .hello span found" );
console.assert( $("#foo").closestDescendant("#foo")[0] === $("#foo")[0], "didn't try to match itself" );
console.assert($("#foo").closestDescendant("span")[0] === $("#correct")[0], "didn't try direct children first");
console.assert($("#start").closestDescendant(".target")[0] === $("#correct2")[0], "didn't try more direct children first");
//Test multiple parents:
console.log( $("#foo, #start").closestDescendant("span") ); //should be the ones with id=correct, correct2