Find Closest Common Ancestor in jQuery

While jQuery does not provide a single built-in method specifically named for finding the common ancestor of two elements, you can easily achieve this by combining native traversal methods. This article covers the most efficient and readable jQuery patterns—primarily utilizing .parents(), .has(), and .closest()—to determine the lowest common ancestor of any two DOM elements.

The Most Reliable Method: .parents().has().first()

The most idiomatic and robust way to find the closest common ancestor in jQuery is:

const $commonAncestor = $(elementA).parents().has(elementB).first();

How It Works:

  1. $(elementA).parents(): Retrieves all ancestor elements of elementA, ordered from the direct parent upwards to the <html> root.
  2. .has(elementB): Filters that list of ancestors to only include elements that contain elementB as a descendant.
  3. .first(): Selects the first matching element in the collection, which represents the nearest (deepest) ancestor shared by both nodes.

Alternative Method: .closest() with Ancestor Collections

Another concise technique passes the ancestor collection of the second element directly into .closest():

const $commonAncestor = $(elementA).closest($(elementB).parents());

How It Works:

  • $(elementB).parents(): Gathers all ancestors of elementB.
  • .closest(...): Traverses up the DOM tree starting from elementA until it finds an element that matches any node in the provided collection.

Note: Because .closest() begins its check with elementA itself, this method will return elementA if elementA happens to be an ancestor of elementB.


Handling Edge Cases (Ancestor-Descendant Relationships)

If one element might directly contain the other, standard traversal must account for whether the parent element itself counts as an ancestor.

If either element can be its own common ancestor:

function getClosestCommonAncestor(a, b) {
    const $a = $(a);
    const $b = $(b);

    // If identical
    if ($a.is($b)) return $a;

    // Check if one contains the other, otherwise find shared parent
    if ($a.has($b).length) return $a;
    if ($b.has($a).length) return $b;

    return $a.parents().has($b).first();
}

Creating a Reusable jQuery Plugin

You can extend jQuery's prototype to make this function accessible across your codebase:

jQuery.fn.commonAncestor = function(target) {
    return this.parents().has(target).first();
};

// Usage:
const $ancestor = $('#item-one').commonAncestor('#item-two');