References

Beginner-friendly references for web development, with live, editable examples.

The JavaScript closest() method

Method JavaScript All modern browsers Updated
Quick answer

The closest() method returns the nearest ancestor — or the element itself — that matches a CSS selector, walking up the DOM tree. event.target.closest(".card") finds the card a clicked element sits inside. It returns null if none matches. It's the backbone of event delegation.

Overview

closest() searches upward through an element's ancestors and returns the first one that matches a CSS selector — checking the element itself first, then its parent, grandparent, and so on. el.closest("li") finds the list item containing el. If nothing up the tree matches, it returns null.

Its killer use is event delegation. Instead of attaching a listener to every button in a list, you put one listener on the container and, when a click fires, use event.target.closest(".item") to find which item was clicked — even if the user clicked an icon or text inside the item. This pattern handles dynamically added elements for free and scales to thousands of items with a single listener.

It's the upward counterpart to querySelector() (which searches downward into descendants). Compared with manually walking parentElement in a loop, closest() is one clean call that also accepts any CSS selector. Its sibling matches() tests whether the element itself matches, without climbing.

Syntax

const ancestor = element.closest(selectors)

btn.closest(".card")           // nearest .card ancestor (or itself)
event.target.closest("li")     // event delegation

Parameters

The closest() method accepts the following parameters.

Parameter Description
selectors A CSS selector string. The method returns the nearest matching ancestor, including the element itself, or null.

Example

Live example
<ul id="menu" style="font:15px system-ui">
  <li>Item with a <button>button</button> inside</li>
  <li>Another <button>button</button></li>
</ul>
<p id="out"></p>
<script>
  // one listener handles every button (delegation)
  document.getElementById('menu').addEventListener('click', (e) => {
    const li = e.target.closest('li');
    if (li) document.getElementById('out').textContent = 'You clicked: ' + li.textContent.trim();
  });
</script>

Best practices

  • Use event.target.closest(selector) for event delegation on a container.
  • Always handle the null case — it's returned when no ancestor matches.
  • Prefer it over manually looping through parentElement.
  • Use matches() when you only need to test the element itself, not its ancestors.

Frequently asked questions

What does closest() do?
It returns the nearest ancestor (or the element itself) that matches a CSS selector, searching up the DOM tree, or null if none match.
How do I use closest() for event delegation?
Listen on a container, then in the handler use event.target.closest(".item") to find which item was clicked, even if a child element was the actual target.
What is the difference between closest() and querySelector()?
closest() searches upward through ancestors; querySelector() searches downward through descendants.
What is the difference between closest() and matches()?
closest() climbs the tree to find a matching ancestor; matches() only tests whether the element itself matches a selector.