DOM Traversals
Hey ,
I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.
Please upgrade (use this link) access this content.
I'm super eager to help you learn more!
Hey ,
I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.
Please upgrade (use this link) access this content.
I'm super eager to help you learn more!
Let’s say you want to go to your neighbor’s house. What’s the fastest and most efficient way to get there?
If you move directly from your house to their house, you’re doing the equivalent of traversing the DOM—selecting one element from a neighboring element.
If you lookup their address on Google, you’re doing the equivalent of document.querySelector to find elements.
Can you guess which method is more efficient?
<div class="neighborhood">
<div class="your-house">😎</div>
<div class="neighbor-house">🎉</div>
</div>
You probably know the answer—it’s always easier to move from an element to another (compared do doing a full search). That’s why we traverse the DOM.
You can traverse in three directions:
There are three ways to traverse downwards:
querySelector or querySelectorAllchildrenfirstElementChildTo traverse downwards from a specific element, you can use element.querySelector or element.querySelectorAll. You already know this.
If we put element.querySelector into the house analogy, we search for a specific room in your house. It’s faster than searching for the same room from outer space (the document).
<div class="component">
<h2 class="component__title">Component title</h2>
</div>
const component = document.querySelector('.component')
const title = component.querySelector('.component__title')
console.log(title) // <h2 class="component__title"> ... </h2>
children is a property that lets you select direct descendants (elements that are immediately nested in another element). It returns a HTML Collection that updates when children elements are changed.
Note: HTML Collections are live collections
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
const list = document.querySelector('.list')
const listItems = list.children
console.log(listItems)
A HTML Collection is a list of HTML Elements. A NodeList is a list of nodes. You can say that a HTML Collection is a subset of a NodeList.
Functions wise, HTML Collections don’t have the forEach method. If you want to loop over a HTML Collection with forEach, you need to convert it into an array with Array.from.
const array = Array.from(HTMLCollection)
array.forEach(el => { /* do whatever you want */})
You can select the nth-item in the list from both NodeLists (result from querySelectorAll) and HTML Collections (result from children). To do so, you use the index of the element, just like how you select a specific item from an Array.
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
const listItems = document.querySelectorAll('li')
const firstItem = listItems[0]
const secondItem = listItems[1]
const thirdItem = listItems[2]
const fourthItem = listItems[3]
const fifthItem = listItems[4]
console.log(firstItem)
console.log(secondItem)
console.log(thirdItem)
console.log(fourthItem)
console.log(fifthItem)
Try the above code with a HTML Collection. You’ll get the same result.
You can select the first element with children like this:
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
const list = document.querySelectorAll('li')
const firstItem = list[0]
You can also select the first element with firstElementChild.
const list = document.querySelector('.list')
const firstItem = list.firstElementChild
There are two ways to traverse upwards:
parentElementclosestparentElement is a property that lets you select the parent element. The parent element is the element that encloses the current element.
In the following HTML, .list is the parent element of all <li>. Each <li> is the parent element of their respective <a>.
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
const firstListItem = document.querySelector('li')
const list = firstListItem.parentElement
console.log(list)
// <ul class="list">...</ul>
parentElement is great for selecting one level upwards. To find an element that can be multiple levels above the current element, you use the closest method.
closest lets you select the closest ancestor element that matches a selector. Here’s the syntax:
const closestAncestor = Element.closest(selector)
As you may suspect, selector is the same selector you pass to querySelector and querySelectorAll.
In the following HTML, you can select .list from the <a> effortlessly with Element.closest:
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
const firstLink = document.querySelector('a')
const list = firstLink.closest('.list')
console.log(list)
// <ul class="list"> ... </ul>
Note: closest starts searching from the current element, then proceeds upwards until it reaches the document. It stops and returns the first element it finds.
const firstLink = document.querySelector('a')
const firstLinkThroughClosest = firstLink.closest('a')
console.log(firstLinkThroughClosest)
// <a href="#">Link 1</a>
closest is pretty new. It doesn’t work on IE Edge 14 and below. It doesn’t work on Opera mini too. If you need to support older browsers, you may want to use a polyfill.
There are three ways to traverse sideways:
nextElementSiblingpreviousElementSiblingparentElement, children, and indexYou can select the next element with nextElementSibling.
const nextElem = Node.nextElementSibling
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
const firstListItem = document.querySelector('li')
const secondListItem = firstListItem.nextElementSibling
console.log(secondListItem)
// <li><a href="#">Link 2</a></li>
Likewise, you can select the previous element with previousElementSibling.
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
const secondListItem = document.querySelectorAll('li')[1]
const firstListItem = secondListItem.previousElementSibling
console.log(firstListItem)
// <li><a href="#">Link 1</a></li>
This method lets you select a specific sibling. It’s easier to explain how it works with an example, so let’s do that. Say you want to select the fourth item from the first item in this HTML.
<ul class="list">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
</ul>
You already have the first item:
const firstItem = document.querySelector('li')
To select the fourth item, you can use firstItem.parentElement to get the list, then list.children to get a HTML Collection. Once you have the HTML Collection, you can find the fourth item by using a index of 3. (Remember, zero-based index!).
const firstItem = document.querySelector('li')
const list = firstItem.parentElement
const allItems = list.children
const fourthItem = allItems[3]
console.log(fourthItem)
// <li><a href="#">Link 4</a></li>
Putting everything together in one step:
const firstITem = document.querySelector('li')
const fourthItem = firstITem.parentElement.children[3]
console.log(fourthItem)
// <li><a href="#">Link 4</a></li>
You learned how to traverse the DOM in three directions—downwards, upwards, and sideways—in this lesson. Here’s a quick bullet point to summarize the methods you learned:
element.querySelectorelement.querySelectorAllelement.childrenelement.parentElementelement.closestelement.nextElementSiblingelement.previousElementSiblingparentElement, children, and indexPractice traversing the DOM with the methods taught in this lesson. With the HTML given below, do these tasks:
.characters with document.querySelector.humans from .charactersquerySelectorAll, starting from .humanschildren.elves from Merry.elves.characters div from Nazgûl<div class="characters">
<ul class="hobbits">
<li>Frodo Baggins</li>
<li>Samwise "Sam" Gamgee</li>
<li>Meriadoc "Merry" Brandybuck</li>
<li>Peregrin "Pippin" Took</li>
<li>Bilbo Baggins</li>
</ul>
<ul class="humans">
<li>Gandalf</li>
<li>Saruman</li>
<li>Aragorn</li>
<li>Boromir</li>
<li>Faramir</li>
</ul>
<ul class="elves">
<li>Legolas</li>
<li>Glorfindel</li>
<li>Elrond</li>
<li>Arwen Evenstar</li>
</ul>
<ul class="enemies">
<li>Sauron</li>
<li>Nazgûl</li>
</ul>
</div>
.characters with document.querySelectorconst characters = document.querySelector('.characters')
.humans from .charactersconst humansList = characters.querySelector('.humans')
querySelectorAll, starting from .humansconst humans = humansList.querySelectorAll('li')
childrenconst hobbitsList = characters.querySelector('.hobbits')
const hobbits = hobbitsList.children
const merry = hobbits[2]
.elves from Merryconst elvesList = merry.parentElement.nextElementSibling.nextElementSibling
.elvesconst glorfindel = elvesList.children[1]
const elrond = glorfindel.nextElementSibling
const legolas = glorfindel.previousElementSibling
.characters div from Nazgûlconst nazgul = document.querySelector('.enemies').chlidren[1]
const characters = nazgul.closest('.characters')