How to Traverse the DOM with JavaScript


The DOM is like a tree of elements. For example, you have some nodes that are nested inside each other, and they kind of branch off. A node nested inside another node is a child, and the node with elements nested under it is a parent.

Here’s an example of some HTML where we can see two children of the body, which are the header and content IDs. The header and content both have some children of their own, including headings and paragraphs.

    <div id="header">
        <h1>Site Title</h1>
    <div id="content">
        <h2>Post Title</h2>
        <p>Some content here.</p>
        <p>Some more text here.</p>

Parent and Element Nodes

If we want to display the #content section’s parent in the console. We can query the dom to select the #content div and use parentNode or parentElement properties to traverse up the DOM to get the content’s parent like so:

const contentParent = document.querySelector('#content');

console.log('Content\'s parent node:', contentParent.parentNode);
console.log('Content\'s Parent element:', contentParent.parentElement);

The above will return the <body> since it’s their parent. It’ll look something like this in the console:

Content's parent node: <body>...</body>
Content's parent element: <body>...</body>

Parent and Element Property Chaining

You can also chain properties together to traverse up the dom two times with .parentNode.parentNode. So, for example, if we wanted to get the body element by querying the DOM for the h2 tag we can chain the node and element properties together like so:

const grandParent = document.querySelector('h2');

console.log('H2\'s grandparent node:', grandParent.parentNode.parentNode);
console.log('H2\'s grandparent element:', grandParent.parentElement.parentElement);

The above will return the body element in the console, which will look like this:

H2's grandparent node: <body>...</body>
H2's grandparent element: <body>...</body>

In the two examples above, we traversed up the DOM by getting the parent nodes and elements, but we can also traverse down the DOM, which is slightly different.

childNodes Property

Using the same HTML at the beginning of the post, let’s log all the children of the #content div. We can do that by using the property .childNodes like so:

const mainContent = document.querySelector('#content');

console.log('The main content\'s children are:', mainContent.childNodes);

In the console, we’ll get a node list object of children that looks like this:

The main content's children are: NodeList(7) [text, h2, text, p, text, p, text]

Above, you can see that there are four instances of text in the NodeList in addition to the children elements, we expected (h2, p, and p). If we click the dropdown and inspect those text nodes further, take a look at the data, textContent, and wholeText rows. Depending on your browser, you’ll see something like this:

The \n represents a new line, and so, the text nodes we see in our nodeList are linebreaks in between the h2 and two p tags.

The point here to remember is that the .childNodes will return whitespace in addition to the elements you’ll want to work with.

children Elements Property

It’s unlikely we’ll want to get and use line breaks so instead of using the .childNodes property to get the nodes we could use the .children property to get the child elements instead.

So let’s get the child elements h2, p, and p of #content:

const mainContent = document.querySelector('#content');

console.log('The main content\'s children are:', mainContent.children);

The above will return an HTML collection of the three elements and looks like this:

Siblings Traversal

In the example, we have a few siblings. Specifically, the header and content IDs are siblings, and the H2 and two paragraphs in the content section are siblings.

We can find the next sibling or previous sibling similar to how to gound the parents and children above. Let’s look at an example:

const h2Sibling = document.querySelector('h2');

console.log('H2\'s next sibling is:', h2Sibling.nextSibling);
console.log('H2\'s next sibling is:', h2Sibling.nextElementSibling);
console.log('H2\'s next sibling is:', h2Sibling.previousSibling);
console.log('H2\'s next sibling is:', h2Sibling.previousElementSibling);
H2's next sibling is: #text
H2's next sibling is: <p>​Some content here.​</p>​
H2's next sibling is: #text
H2's next sibling is: null

We can see again, like the childNode property the nextSibling and previousSibling also returns the text whitespace/return character, but using the element option returns the next or previous child elements.

Also, notice that the h2Sibling.previousElementSibling in the case of our H2 is null, since the H2 only has next siblings but no previous ones.

Additional Resources:

Leave a Reply

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