JavaScript DOM Traversal

DOM traversal means moving through the structure of an HTML page using JavaScript — going up to parent elements, down to children, or sideways to siblings. The browser represents every HTML page as a tree of nodes, and traversal lets you navigate that tree without hardcoding selectors for every element.

The DOM as a Family Tree

Think of HTML elements as a family. A <div> containing two <p> tags is a parent with two children. The two <p> tags are siblings. Traversal moves you through these relationships dynamically.

Diagram: DOM Tree Structure

<div id="container">
  <h2>Title</h2>
  <p>First paragraph</p>
  <p>Second paragraph</p>
</div>

             div#container
            /      |      \
          h2       p       p
        "Title"  "First" "Second"

  h2 and p are children of div
  h2, p, p are siblings of each other
  div is the parent of all three

Moving to the Parent

parentElement

let p = document.querySelector("p");
console.log(p.parentElement); // the div containing p

// Chain up multiple levels
console.log(p.parentElement.parentElement); // the parent of the div

closest( ) — Walk Up to the First Match

closest() starts from the current element and walks up the DOM tree, returning the first ancestor that matches the given selector.

<!-- HTML -->
<div class="card">
  <div class="card-body">
    <button class="btn-delete">Delete</button>
  </div>
</div>
let btn = document.querySelector(".btn-delete");
let card = btn.closest(".card");
console.log(card); // the div.card element

Diagram: closest() Walking Up

Start: .btn-delete

  .btn-delete → is it .card? NO → go up
  .card-body  → is it .card? NO → go up
  .card       → is it .card? YES → return it

Moving to Children

children — Only Element Nodes

let container = document.querySelector("#container");

console.log(container.children);       // HTMLCollection of child elements
console.log(container.children[0]);    // first child element
console.log(container.children.length); // number of children

firstElementChild / lastElementChild

let list = document.querySelector("ul");
console.log(list.firstElementChild); // first <li>
console.log(list.lastElementChild);  // last <li>

childNodes — Includes Text Nodes Too

childNodes includes text nodes (whitespace, newlines) between elements. Use children when you want only element nodes.

// childNodes can return unexpected text nodes
// children only returns actual HTML elements — usually safer

Moving to Siblings

nextElementSibling / previousElementSibling

<!-- HTML -->
<ul>
  <li>Item 1</li>
  <li id="second">Item 2</li>
  <li>Item 3</li>
</ul>
let second = document.getElementById("second");

console.log(second.nextElementSibling.textContent);     // "Item 3"
console.log(second.previousElementSibling.textContent); // "Item 1"

Diagram: Sibling Navigation

<li>Item 1</li>  ← previousElementSibling
<li>Item 2</li>  ← current element (second)
<li>Item 3</li>  ← nextElementSibling

Full Traversal Reference

Property / MethodDirectionReturns
parentElementUpParent element
closest(selector)UpFirst matching ancestor
childrenDownAll child elements
firstElementChildDownFirst child element
lastElementChildDownLast child element
nextElementSiblingSidewaysNext sibling element
previousElementSiblingSidewaysPrevious sibling element

Practical Example: Highlight the Clicked List Item and Its Neighbors

let items = document.querySelectorAll("li");

items.forEach(function(item) {
  item.addEventListener("click", function() {
    // Remove previous highlights
    items.forEach(i => i.style.background = "");

    // Highlight the clicked item
    item.style.background = "yellow";

    // Highlight the next sibling
    if (item.nextElementSibling) {
      item.nextElementSibling.style.background = "lightyellow";
    }

    // Highlight the previous sibling
    if (item.previousElementSibling) {
      item.previousElementSibling.style.background = "lightyellow";
    }
  });
});

Diagram: Click on "Item 2" Result

Before click:
  [ Item 1 ]  [ Item 2 ]  [ Item 3 ]

After clicking "Item 2":
  [ Item 1 lightyellow ]  [ Item 2 yellow ]  [ Item 3 lightyellow ]
    previousSibling           clicked            nextSibling

Event Delegation with Traversal

Instead of attaching listeners to every child, attach one listener to the parent and use traversal to find what was clicked.

<!-- HTML -->
<ul id="todo-list">
  <li>Buy groceries <button class="done-btn">Done</button></li>
  <li>Read a book <button class="done-btn">Done</button></li>
</ul>
let list = document.getElementById("todo-list");

list.addEventListener("click", function(event) {
  if (event.target.classList.contains("done-btn")) {
    // Walk up from the button to its parent li
    let listItem = event.target.closest("li");
    listItem.style.textDecoration = "line-through";
  }
});

Diagram: Event Delegation Flow

User clicks "Done" button inside li:
  event.target = .done-btn button
        │
  .closest("li") walks up
        │
  Finds parent <li>
        │
  Applies strikethrough to the whole li

Looping Over Children

let nav = document.querySelector("nav");

// Loop over all direct children
Array.from(nav.children).forEach(function(child) {
  console.log(child.tagName, child.textContent);
});

Summary

DOM traversal lets you move through an HTML page's tree structure without querying the DOM every time with a new selector. Use parentElement and closest() to go up, children and firstElementChild to go down, and nextElementSibling with previousElementSibling to move sideways. Traversal is especially powerful for event delegation, where a single parent listener handles events for many children dynamically.

Leave a Comment

Your email address will not be published. Required fields are marked *