jQuery & DOM Manipulation

Traversing Down the DOM

12 min Lesson 7 of 30

Understanding Downward DOM Traversal

While upward traversal moves from child to parent, downward traversal moves from parent to descendants - children, grandchildren, and beyond. This is essential when you need to find, modify, or interact with elements nested inside a container.

Downward traversal is one of the most common operations in jQuery, used for everything from finding specific elements within a section to manipulating all items in a list.

Why Traverse Downward?

  • Scope operations: Limit changes to elements within a specific container
  • Find nested elements: Locate deeply nested items without affecting others
  • Iterate over children: Apply operations to all child elements
  • Performance: Search within a small scope instead of the entire document
Note: Downward traversal methods are more efficient when you start with a specific container rather than searching the entire document. Always narrow your scope when possible.

The children() Method

The children() method returns the direct children of each element in the matched set. It goes down exactly one level, ignoring grandchildren and deeper descendants.

HTML Structure: <ul class="menu"> <li class="item">Home</li> <li class="item"> About <ul class="submenu"> <li>Team</li> <li>History</li> </ul> </li> <li class="item">Contact</li> </ul> jQuery: // Get direct children of .menu (returns only the 3 top-level li elements) $(".menu").children(); // Get only li children (same result in this case) $(".menu").children("li"); // Add a class to all direct children $(".menu").children().addClass("top-level"); // Note: This does NOT select the nested li elements in .submenu
Tip: children() is much faster than find() because it only searches one level deep. Use it when you only need immediate children.

The find() Method

The find() method searches for all descendants at any depth - children, grandchildren, great-grandchildren, and so on. It's the most powerful downward traversal method and requires a selector.

HTML Structure: <div class="container"> <div class="section"> <p class="text">Paragraph 1</p> <div class="nested"> <p class="text">Paragraph 2</p> </div> </div> </div> jQuery: // Find all .text descendants (returns both paragraphs) $(".container").find(".text"); // Find all divs at any level $(".container").find("div"); // Chain with other methods $(".container").find("p").css("color", "blue"); // Find is required - you must provide a selector $(".container").find(); // ERROR: selector is required
Important: find() requires a selector argument. Unlike children(), you cannot call it without parameters. Always specify what you're looking for.

Comparison: children() vs find()

HTML: <div class="box"> <p>Direct child</p> <div> <p>Grandchild</p> </div> </div> jQuery: // children() - returns only the direct p and div $(".box").children(); // [<p>, <div>] // children() with selector - returns only direct p $(".box").children("p"); // [<p>Direct child</p>] // find() - returns both p elements at any depth $(".box").find("p"); // [<p>Direct child</p>, <p>Grandchild</p>]

The contents() Method

The contents() method returns all direct children including text nodes and comments. This is different from children(), which only returns element nodes.

HTML: <div class="wrapper"> Some text <span>A span</span> More text </div> jQuery: // children() returns only the span $(".wrapper").children(); // [<span>] // contents() returns text nodes AND the span $(".wrapper").contents(); // [text, <span>, text] // Useful for iframes $("iframe").contents().find("body"); // Access iframe contents
Tip: contents() is particularly useful for working with iframes, as it allows you to access and manipulate the iframe's document.

Practical Example: Collapsible Sections

HTML: <div class="faq"> <div class="faq-item"> <h3 class="faq-question">What is jQuery?</h3> <div class="faq-answer">jQuery is a JavaScript library...</div> </div> <div class="faq-item"> <h3 class="faq-question">How do I install jQuery?</h3> <div class="faq-answer">You can include it via CDN...</div> </div> </div> jQuery: $(".faq-question").on("click", function() { // Find the answer within the same faq-item var faqItem = $(this).parent(); // Toggle the answer (direct child of faq-item) faqItem.children(".faq-answer").slideToggle(); // Or use find() to search deeper if structure changes // faqItem.find(".faq-answer").slideToggle(); });

Practical Example: Form Validation

HTML: <form class="registration-form"> <div class="form-section"> <h3>Personal Info</h3> <input type="text" name="name" required> <input type="email" name="email" required> </div> <div class="form-section"> <h3>Address</h3> <input type="text" name="street" required> <input type="text" name="city" required> </div> </form> jQuery: $(".registration-form").on("submit", function(e) { var isValid = true; // Find all required inputs in the form $(this).find("input[required]").each(function() { if ($(this).val() === "") { $(this).addClass("error"); isValid = false; } else { $(this).removeClass("error"); } }); if (!isValid) { e.preventDefault(); alert("Please fill all required fields"); } }); // Validate specific section $(".form-section").first().find("input").each(function() { console.log($(this).attr("name")); });

Practical Example: Dynamic Lists

HTML: <div class="todo-list"> <ul class="tasks"> <li class="task"> <span class="task-text">Buy groceries</span> <button class="delete-btn">Delete</button> </li> <li class="task"> <span class="task-text">Walk the dog</span> <button class="delete-btn">Delete</button> </li> </ul> <button class="add-task-btn">Add Task</button> </div> jQuery: // Count all tasks var taskCount = $(".todo-list").find(".task").length; console.log("Total tasks: " + taskCount); // Get all task texts $(".todo-list").find(".task-text").each(function() { console.log($(this).text()); }); // Mark all tasks as completed $(".todo-list").find(".task").addClass("completed"); // Delete all tasks in the list $(".clear-all-btn").on("click", function() { $(".tasks").children(".task").remove(); });

Practical Example: Image Gallery

HTML: <div class="gallery"> <div class="gallery-row"> <img src="image1.jpg" alt="Photo 1"> <img src="image2.jpg" alt="Photo 2"> </div> <div class="gallery-row"> <img src="image3.jpg" alt="Photo 3"> <img src="image4.jpg" alt="Photo 4"> </div> </div> jQuery: // Add lightbox to all images $(".gallery").find("img").on("click", function() { var src = $(this).attr("src"); var lightbox = $("<div class='lightbox'></div>"); var img = $("<img>").attr("src", src); lightbox.append(img).appendTo("body"); }); // Count images in each row $(".gallery").children(".gallery-row").each(function(index) { var imageCount = $(this).children("img").length; console.log("Row " + (index + 1) + " has " + imageCount + " images"); }); // Add lazy loading to all images $(".gallery").find("img").attr("loading", "lazy");

Performance Comparison

Scenario: Finding an element nested 3 levels deep // SLOW - searches entire document var element = $(".deeply-nested-element"); // FASTER - starts from a known container var element = $(".container").find(".deeply-nested-element"); // FASTEST - if you know exact path var element = $(".container").children(".level1") .children(".level2") .children(".level3");
Performance Tip: Always start your search from the smallest possible scope. Finding elements within a container is much faster than searching the entire document.

Comparison Table

Method Search Depth Returns Best Used For
children() One level Direct children only Fast access to immediate children
find() All levels All descendants Finding deeply nested elements
contents() One level Children + text nodes Working with iframes or text nodes

Practice Exercise

Scenario: Create a product filter that shows/hides products based on category.

HTML Structure:
<div class="shop"> <div class="filters"> <button class="filter-btn" data-category="all">All</button> <button class="filter-btn" data-category="electronics">Electronics</button> <button class="filter-btn" data-category="clothing">Clothing</button> </div> <div class="products"> <div class="product" data-category="electronics"> <img src="laptop.jpg"> <h3>Laptop</h3> <p class="price">$999</p> </div> <div class="product" data-category="clothing"> <img src="shirt.jpg"> <h3>T-Shirt</h3> <p class="price">$29</p> </div> <div class="product" data-category="electronics"> <img src="phone.jpg"> <h3>Phone</h3> <p class="price">$699</p> </div> </div> </div>
Your Tasks:
  1. When a filter button is clicked, get its data-category value
  2. Use find() to get all products within .shop
  3. Show all products if category is "all"
  4. Otherwise, hide products that don't match the category
  5. Bonus: Count visible products and display the count
  6. Bonus: Add a "featured" badge to products under $100
Hint: Use $(this).closest(".shop").find(".product") to scope your search, then filter by [data-category] attribute.

Key Takeaways

  • children() is fast and specific - use it for immediate children
  • find() searches all levels - required selector, more flexible
  • contents() includes text nodes - useful for iframes
  • Always narrow your search scope for better performance
  • Start from a container instead of searching the entire document
  • Downward traversal is essential for scoped operations and bulk updates

ES
Edrees Salih
13 hours ago

We are still cooking the magic in the way!