Himanshu SharmaSoftware engineer
Let’s talk

jQuery · Lesson 7 of 45

Traversing up and down: closest and find

Go up the DOM with jQuery .parent(), .parents() and .closest(), and down with .children() and .find(), to reach elements related to the one you have.

12 minSelecting elementsUpdated 23 October 2026

By the end of this lessonStart from any element, such as the button that was clicked, and reach its container or the elements inside it reliably.

Why traverse?

Selectors search the whole page. Very often, though, you already have one element, typically the button someone just clicked, and you need something related to it: the card it sits in, the row of the table, the input next to it. Moving from one element to its relatives is called traversing the DOM.

This lesson goes up and down the tree. The next goes sideways.

The family tree

Here is the HTML used in the examples:

html
<div class="product" id="p1">
  <h3 class="name">Desk lamp</h3>
  <div class="details">
    <span class="price">1200</span>
    <button class="add">Add to cart</button>
  </div>
</div>

The button is a child of .details, which is a child of .product. Going the other way, .product is the button's ancestor, and the button is a descendant of .product.

Going up

html
<div class="product" id="p1">
  <h3 class="name">Desk lamp</h3>
  <div class="details">
    <span class="price">1200</span>
    <button class="add">Add to cart</button>
  </div>
</div>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $button = $(".add");
  console.log("parent:", $button.parent().attr("class"));
  console.log("parents:", $button.parents().map((i, el) => el.tagName.toLowerCase() + (el.className ? "." + el.className : "")).get().join(" < "));
  console.log("parents('.product'):", $button.parents(".product").attr("id"));
  console.log("closest('.product'):", $button.closest(".product").attr("id"));
  console.log("closest('button'):", $button.closest("button").attr("class"));
</script>
result
parent: details
parents: div.details < div.product < body < html
parents('.product'): p1
closest('.product'): p1
closest('button'): add
  • .parent() moves one level up.
  • .parents() returns every ancestor, up to html. Give it a selector to keep only matching ones.
  • .closest(selector) walks up from the element itself and stops at the first match. It returns at most one element per starting element.

.closest() is the one you will use most, because it does not care how deep the button is buried.

The click pattern

Here is the real reason traversal matters. Several products share the same button class, and each click must affect only its own product:

html
<div class="product" id="p1"><h3 class="name">Desk lamp</h3><button class="add">Add</button></div>
<div class="product" id="p2"><h3 class="name">Notebook</h3><button class="add">Add</button></div>
<div class="product" id="p3"><h3 class="name">Pen set</h3><button class="add">Add</button></div>
<p id="log"></p>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  $(".add").on("click", function () {
    const $product = $(this).closest(".product");
    const name = $product.find(".name").text();
    $product.css("outline", "2px solid green");
    $("#log").text("Added: " + name);
    console.log("clicked in", $product.attr("id"));
  });
</script>
result
clicked in p2

this is the button that was clicked. From it, .closest(".product") reaches its own card, and .find(".name") reads the name inside that card only. This "up to the container, then down to what you need" move appears in nearly every interactive page.

Going down

html
<ul id="menu">
  <li>Home</li>
  <li>Shop
    <ul>
      <li>Lamps</li>
      <li>Desks</li>
    </ul>
  </li>
  <li>Contact</li>
</ul>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $menu = $("#menu");
  console.log("children():", $menu.children().length);
  console.log("children('li'):", $menu.children("li").length);
  console.log("find('li'):", $menu.find("li").length);
  console.log("find('ul li'):", $menu.find("ul li").text());
</script>
result
children(): 3
children('li'): 3
find('li'): 5
find('ul li'): LampsDesks
  • .children() returns direct children only: the three top-level items.
  • .find(selector) searches all levels below and needs a selector: it found all five list items.

Why not count parents?

You will see code like this in old projects:

javascript
const $row = $(this).parent().parent();

It works until someone wraps the button in a <span> for styling. Then .parent().parent() lands on the wrong element and the code fails, often silently. $(this).closest("tr") keeps working because it searches until it finds a row. Write traversal that describes what you want, not how many steps away it is.

Plain JavaScript equivalents

The browser has matching tools, useful when you read modern code:

jQuery Plain JavaScript
$(el).parent() el.parentElement
$(el).closest(".card") el.closest(".card")
$(el).children() el.children
$(el).find(".name") el.querySelectorAll(".name")

The jQuery versions work on many elements at once and never throw when nothing matches.

Common mistakes

  • Using .parents() when you want one element. It can return several; use .closest().
  • Calling .find() with no selector, which returns nothing.
  • Using .children() to reach deeply nested elements. It only looks one level down.
  • Selecting from the whole page inside a click handler, such as $(".name"), which reads every product's name instead of the clicked one.

Exercise

You have a table where each row has a name cell and a Delete button. Write a click handler that logs the name in the same row as the button that was clicked.

Show one possible answer
html
<table>
  <tr><td class="who">Asha</td><td><button class="del">Delete</button></td></tr>
  <tr><td class="who">Ben</td><td><button class="del">Delete</button></td></tr>
</table>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  $(".del").on("click", function () {
    const name = $(this).closest("tr").find(".who").text();
    console.log(name);
  });
</script>

Key points

  • .parent() goes up one level; .parents() returns every ancestor; .closest(selector) returns the nearest ancestor that matches, starting with the element itself.
  • .children() returns direct children only; .find(selector) searches every level below.
  • Traversing is how you find the right card, row or form for the button that was clicked.
  • Prefer .closest() and .find() over long chains of .parent().parent(), which break when the HTML changes.

Check yourself

1. What does .closest(".card") check first?
2. What is the difference between .children() and .find()?
3. Why is .closest("tr") better than .parent().parent()?
4. What does .find() require?