Replace jQuery .closest() with Vanilla JavaScript

Transitioning away from jQuery often leaves developers looking for modern, native alternatives to its most popular DOM traversal methods. This guide explains how modern vanilla JavaScript completely replaces the jQuery .closest() method using the standard Element.closest() API, detailing its syntax, behavior, event delegation patterns, and browser support.

The Native Alternative: Element.closest()

Modern browsers provide a native DOM method called Element.closest(). It works virtually identically to jQuery's implementation: it checks the current element against a specified CSS selector, and if it does not match, it traverses up the DOM tree through ancestor elements until a match is found. If no match is found, it returns null.

Syntax Comparison

jQuery

// jQuery
const closestCard = $('.child-element').closest('.card');

Vanilla JavaScript

// Vanilla JS
const child = document.querySelector('.child-element');
const closestCard = child.closest('.card');

Key Differences and Behavior

  1. Return Value:
    • jQuery returns a jQuery object, which is always truthy, even if no element matched (in which case its .length is 0).
    • Vanilla JS returns the matching DOM element, or null if no match exists. Always check for null before interacting with the result.
const button = document.querySelector('button');
const modal = button.closest('.modal');

if (modal) {
  modal.classList.add('is-active');
}
  1. Self-Matching: Like jQuery, native closest() tests the calling element itself first before inspecting parent elements. If the element calling the method matches the selector, that element is returned immediately.

Event Delegation with Element.closest()

One of the most common use cases for .closest() in jQuery is event delegation. In vanilla JavaScript, you can achieve the same behavior using the event.target property inside a standard event listener:

document.addEventListener('click', (event) => {
  // Find closest button ancestor or the button itself
  const button = event.target.closest('.action-btn');

  // If the click happened outside of any .action-btn, exit
  if (!button) return;

  // Perform action using the matched element
  console.log('Button clicked:', button.dataset.id);
});

This pattern handles nested elements inside buttons (such as <span> tags or SVG icons) seamlessly without needing separate event listeners on every item.

Browser Compatibility

The native Element.closest() method is supported across all modern browsers, including Chrome, Firefox, Safari, and Edge. Polyfills are only required if you need to support legacy browsers such as Internet Explorer 11.