Skip to main content

How to Iterate Over All DOM Elements in JavaScript

Iterating over every single element in the Document Object Model (DOM) is a powerful technique for tasks like searching for specific content, applying a global style change, or building a web scraper. While you can get a "flat" list of all elements, a more common and useful approach is to traverse the DOM tree recursively.

This guide will demonstrate the modern and most robust method for visiting every DOM element by creating a recursive "tree walker" function. We will also cover the simpler querySelectorAll('*') method for getting a flat list of all elements.

The Core Task: Visiting Every Element

The goal is to write a function that can start at a given "root" element (like document.body) and visit that element and every single one of its descendants in a predictable order.

For example, you need to perform an action on every element within the <body>.

<body>
<header>
<h1>Title</h1>
</header>
<main>
<div>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</div>
</main>
</body>
note

We want to write a script that can visit <body>, <header>, <h1>, <main>, <div>, <p>, and <p>.

This is the most powerful and flexible approach. A recursive function is one that calls itself, which is a natural fit for traversing a tree-like structure like the DOM.

Solution: this function takes a starting element and a callback function. It calls the callback for the starting element and then recursively calls itself for each of that element's children.

/**
* Traverses the DOM tree starting from a given element.
* @param {Element} element The root element to start traversal from.
* @param {Function} callback A function to call for each element found.
*/
function walkTheDOM(element, callback) {
// 1. Perform the action on the current element
callback(element);

// 2. Recursively call the function for each child element
for (const child of element.children) {
walkTheDOM(child, callback);
}
}

// Example Usage:
// Start the traversal from the document body
walkTheDOM(document.body, (element) => {
console.log(element.tagName);
});
note

This will log the tag name of every element within the <body>, giving you a complete traversal of the tree.

The "Flat List" Method: querySelectorAll('*')

If you don't need the hierarchical relationship and just want a simple, flat list of all elements, you can use document.querySelectorAll('*'). The universal selector (*) matches every element.

// Get a static NodeList of every element in the document
const allElements = document.querySelectorAll('*');

// Iterate over the list
for (const element of allElements) {
// This will include <html>, <head>, <body>, etc.
console.log(element.tagName);
}

::: Important Distinction:

  • document.querySelectorAll('*'): Gets all elements in the entire document, including <html>, <head>, <meta>, <title>, etc.
  • document.body.querySelectorAll('*'): Gets all elements inside the <body>, but not the <body> element itself. :::

The recursive walkTheDOM function gives you more control over the starting point and the traversal process.

How the Recursive Method Works

The walkTheDOM function is a classic example of recursion:

  1. Base Action: When the function is called, it first performs its action (the callback) on the element it was given.
  2. Recursive Step: It then iterates through the element.children collection. The children property contains only the direct child elements (ignoring text nodes, comments, etc.).
  3. For each child element, it calls itself (walkTheDOM(child, ...)), which starts the process over again for that child.
  4. Base Case: The recursion stops naturally when an element has no children. The for...of loop will simply not run, and the function will return, allowing the previous call in the stack to continue to its next child.

Practical Example: Finding All Elements with a Specific Data Attribute

This is a perfect use case for a DOM walker. The script will traverse the entire body and create a list of all elements that have a data-component attribute.

function walkTheDOM(element, callback) {
callback(element);
for (const child of element.children) {
walkTheDOM(child, callback);
}
}

const componentElements = [];

// Start the walk from the document body
walkTheDOM(document.body, (element) => {
// Check if the element has the 'data-component' attribute
if (element.hasAttribute('data-component')) {
componentElements.push(element);
}
});

console.log('Found component elements:', componentElements);
note

This is a clean and efficient way to query the entire DOM for elements that match a custom JavaScript-based criterion, which is something a simple CSS selector cannot always do.

Conclusion

Iterating over all DOM elements is a powerful technique for global queries and manipulations.

  • The recursive "tree walker" function is the recommended best practice. It is highly flexible, provides a logical traversal of the DOM hierarchy, and allows you to perform complex actions on each element.
  • The querySelectorAll('*') method is a simpler alternative that provides a flat NodeList of all elements. It is useful when you just need a list and don't care about the hierarchical structure.

By using a recursive traversal, you can write powerful scripts that can reliably interact with every element on a page.