JavaScript Fundamentals: Master the DOM! (Part 2)

Timothy Robards
Mar 7, 2019 · 11 min read

In this article, we’re going to learn all about traversing DOM elements as well as making changes to DOM elements. We’re following on from Master the DOM! (Part 1). So let’s get started!

This article is part of a series I’m writing on learning the JavaScript fundamentals. Be sure to follow me if you’d like to keep track!

Traversing the DOM

When we traverse the DOM, we’re essentially navigating through the DOM. We work with parent, child and sibling properties to apply our JavaScript to DOM elements.

We’ll be using a new example, as follows:

<!DOCTYPE html>
<html>
<head>
<title>Traversing the DOM</title>
</head>
<body>
<h1>Traversing the DOM</h1>
<p>Let's work with this example to <strong>MASTER</strong> the DOM!</p>
<h2>List of Items..</h2>
<ul>
<li>Pizza</li>
<li>Burgers</li>
<li>Doritos</li>
</ul>
</body>
<script>
const h1 = document.getElementsByTagName('h1')[0];
const p = document.getElementsByTagName('p')[0];
const ul = document.getElementsByTagName('ul')[0];
</script>
</html>

Our file will open up in the browser like so:

Root Nodes

The document object is the root of every node in the DOM. The next level up is the window object — which includes things such as browser tabs, toolbars, prompts and alerts. We’ll be working with the DOM and thus the document object, which consists of what is inside of the inner window.

By default, every document contains the html, head, and body elements.

Check the contents of each by running the following in your console:

document.head;     // ► <head>...</head>
document.body; // ► <body>...</body>

Parent Nodes

As mentioned earlier, the nodes in the DOM are referred to as parents, children, and siblings, depending on their relation to other nodes. The parent of any particular node is the node that is one level above it in the DOM hierarchy.

In our example:

  • html is the parent of head, body, and script.
  • body is the parent of h1, h2, p and ul, but not li, asli is two levels down from body.

We can check the parent of our p element for example, with the parentNode property. As we’ve assigned p to a variable all we need to do is type:

p.parentNode;      // ► <body>...</body>

We can even go two levels up with:

p.parentNode.parentNode;      // ► <html>...</html>

Child Nodes

The children of a node are the nodes that are one level below. Any nodes beyond one level of nesting are usually referred to as descendants.

There are a number of properties we’ll often be working with here, such as childNodes, firstChild, lastChild, children, firstElementChild and lastElementChild.

Lets start with the childNodes property, it will return a list of every child of a given node:

ul.childNodes   // ► NodeList(7) [text, li, text, li, text, li, text]

Perhaps you we’re expecting just three li’s to be returned? The text nodes are actually whitespace caused by indentation between elements — which the DOM considers as nodes. You can’t see them under your Elements tab, as Dev Tools removes these nodes automatically.

For this reason, if we attempt to alter the background color of the first child node for example, it’d fail as the first child is text.

ul.firstChild.style.background = "purple";// output:Uncaught TypeError: Cannot set property 'background' of undefined

When we want to work with element nodes only, we should use the children, firstElementChild and lastElementChild properties.

ul.children would return only the three li elements.

And to change just our first li, we’d use:

ul.firstElementChild.style.background = 'purple';

Here’s our updated page:

If we want to alter all of our children elements, we could use a for...of loop like so:

for (let element of ul.children) {
element.style.background = 'purple';
}

Now all our child elements have the background color change:

If we take a look at our p element, we’ll see it contains both text and other elements (our strong tag).

for (let element of p.childNodes) {
console.log(element);
}
// output:"Let's work with this example to "
<strong>MASTER</strong>
" the DOM!"

The childNodes property is useful when we wish to access that information.

Both childNodes and children do not return traditional JavaScript arrays (with all their associated properties & methods), but rather array-like objects. As you would with an array, however, you can access nodes by index number, or even find their length property.

document.body.children[3].lastElementChild.style.background = 'pink';

With this code, we’ll find the last element child li of the fourth child element ul of body and apply our style..

By using parent and child properties, you can retrieve any node in the DOM!

Sibling Nodes

Let’s now take a look at sibling nodes. Siblings of a node are any node on the same tree level in the DOM. They don’t have to be the same type of node — text, element, and comment nodes can all be siblings. The properties we’ll often work with here are nextSibling, previousSibling, nextElementSibling and previousElementSibling.

Sibling properties work in the same way as child nodes: previousSibling and nextSibling will get the next node that immediately precedes or follows the specified node, and previousElementSibling and nextElementSibling will only get element nodes.

Let’ s get the middle element from our ul:

const burger = ul.children[1];

And let’s use the element sibling properties to access the next and previous elements (avoiding the whitespace text):

burger.nextElementSibling.style.background = 'orange';
burger.previousElementSibling.style.background = 'green';

These changes will now show in our example:

Making Changes to the DOM

Let’s now take a look at how we can add, change, replace and remove nodes from the DOM. We’ll be looking specifically at the createElement() and createTextNode() methods, as well as node.textContent & node.innerHTML.

Creating New Nodes

In this section, we’ll work with the following HTML:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Master the DOM!</title>
</head>
<body>
<h1>Master the DOM!</h1>
</body>
</html>

Open up the Console tab in Developer Tools.

Let’s use the createElement() method on the document object to create a new p element.

const paragraph = document.createElement('p');console.log(paragraph);     // <p></p>

Success! The paragraph variable gives us our p element.

We can now add text to our element, with the textContent property:

paragraph.textContent = "I'm a paragraph!";console.log(paragraph);     // <p>I'm a paragraph!</p>

Thus, by combining createElement() and textContent we can create a complete element node.

We could also use the innerHTML property to add content to an element. With this property we can add both text and HTML to our element:

paragraph.innerHTML = "I'm a <strong>bold</strong> paragraph!";

Of the two methods, textContent is superior — it’s slightly faster to render than innerHTML.

It’s also possible to create a text node using the createTextNode() method:

const text = document.createTextNode("I'm a text node!");console.log(text);    // "I'm a text node!"

All of these methods have created new elements and text nodes, however, they are not visible on the front end of a website until they’ve been inserted into the document!

Inserting Nodes into the DOM

To see the new text nodes and elements we create on the front end, we need to insert them into the document. The methods appendChild() & insertBefore() are used to add items to the beginning, middle, or end of a parent element, and replaceChild() is used to replace an old node with a new node.

Lets demo this by adding a list to our HTML:

<ul>
<li>Get pizza</li>
<li>Get burgers</li>
<li>Get Doritos</li>
</ul>

And here’s our page:

Say we want to add a new item to the end of our list, we have to create the element and add text to it first, as we did previously, like so:

// Get the ul element
const list = document.querySelector('ul');
// Create new list item
const newItem = document.createElement('li');
newItem.textContent = 'Get nice cheese';

We now have a complete element for our new list item! So we can add it to the end of the list using appendChild():

// Add our new item to the end of the list
list.appendChild(newItem);

And our new li element has been appended to the end of the ul:

To add an item to the beginning of our list, let’s create another element (we have to again create a new element, as createElement() can‘t be reused):

// Create a new list item
const anotherNewItem = document.createElement('li');
anotherNewItem.textContent = 'Get Party Whistles';

We use the insertBefore() method to add it to the beginning of our list. It will take two arguments, the first being the new child node to be added, and the second is the sibling node that will immediately follow.

parentNode.insertBefore(newNode, nextSibling);

So for our example, we’ll add the new anotherNewItem element to the start of our list, like so:

// Add new item to the beginning of the list
list.insertBefore(anotherNewItem, list.firstElementChild);

And now our new node has been added to the start of our list!

Let’s also take a look at how we can replace an existing node with a new node using replaceChild(). First, we create the new element:

const modifiedItem = document.createElement('li');
modifiedItem.textContent = "Get Poppin' Jalapeno Doritos";

replaceChild() also takes two arguments, first the new node, then the node to be replaced..

parentNode.replaceChild(newNode, oldNode);

In our example, we’re replacing the third element child on our list:

// Replace list item
list.replaceChild(modifiedItem, list.children[3])

Using a combination of appendChild(), insertBefore(), and replaceChild(), we can insert nodes and elements anywhere in the DOM!

Removing Nodes from the DOM

To remove nodes from the DOM, we can use removeChild() to remove child nodes from their parent, or we can use remove() to remove the node itself.

Returning to our example, lets remove the last item on our list:

// Remove the last list item
list.removeChild(list.lastElementChild);

And the result:

Alternatively, we could use remove(), to remove the node itself:

// Remove the third element from our list
list.children[2].remove();

Using removeChild() and remove(), you can remove any node from the DOM.

Modifying Attributes, Classes, and Styles in the DOM

In this final section, we’ll take a look at how we can modify the attributes, classes and styles of HTML element nodes.

Modifying Attributes

Attributes are often used in HTML to provide additional information about an element. Some common examples are the src attribute of an img tag, the href of an a tag, as well as class, id and style. You may also have seen attributes beginning with data-, these are custom attributes that we can also modify.

The methods we have in JavaScript for modifying element attributes, are:

hasAttribute() — Returns a Boolean.

getAttribute() — Returns the value of a specific attribute.

setAttribute() — Adds or updates the value of a specific attribute.

removeAttribute() — Removes an attribute from an element.

Let’s use the following HTML as our example:

<!DOCTYPE html>
<html lang="en">
<body>
<img src="https://res.cloudinary.com/trobes/image/upload/c_scale,w_400/v1549941322/before.png"></body></html>

Open up the console and test out the attribute methods:

// Assign image element
const image = document.querySelector('img');
image.hasAttribute('src'); // true
image.getAttribute('src'); // returns the src link
image.removeAttribute('src'); // removes the src

And lets use setAttribute() to assign a new image to our src:

image.setAttribute('src', 'https://res.cloudinary.com/trobes/image/upload/c_scale,w_400/v1549941322/after.png');

The hasAttribute() and getAttribute() methods are often used with with conditional statements, while setAttribute() and removeAttribute() are more often used to directly modify the DOM.

Modifying Classes

When working with CSS, we use classes to apply styles to multiple elements. Let’s take a look at how we can work with the class attribute in JavaScript, using className and classList.

className — Gets or sets the class value.

classList.add() — Adds class values.

classList.toggle() — Toggles a class on or off.

classList.contains() — Checks if a value exists.

classList.replace() — Replaces old value with a new one.

classList.remove() — Removes a value.

Let’s work with each of these methods in the following example:

<!DOCTYPE html>
<html lang="en">
<style>
.active {
border: 5px solid green;
}
.alert {
border: 5px solid red;
}
.hidden {
display: none;
}
div {
border: 5px solid lightgrey;
padding: 15px;
margin: 5px;
}
</style>
<body>
<div>Div #1</div>
<div class="active">Div #2</div>
</body>
</html>

And here’s the initial HTML output:

We use className to assign values to classes:

// Select div #1
const div = document.querySelector('div');
// Assign the alert class to div #1
div.className = 'alert';

Now the alert class defined in our HTML, has been assigned to the first div:

This will override any existing classes on the element. You can add multiple classes using className, if you separate the class names to be applied with spaces.

The other way to modify our classes is with the classList property, it has a few very useful methods:

// Select div #2 by its class name
const activeDiv = document.querySelector('.active');
// Add the hidden class
activeDiv.classList.add('hidden');

// Remove the hidden class
activeDiv.classList.remove('hidden');

// Switch between hidden true and false
activeDiv.classList.toggle('hidden');
// Replace active class with alert class
activeDiv.classList.replace('active', 'alert');

After running through these methods, our HTML will render like so:

Note: Using classList.add() will add a new class to the list of existing classes (remember className would override any existing classes). You can also add multiple classes as comma-separated strings.

Modifying Styles

Typically styles are added via separate CSS stylesheets, however there are times when we might want to use an inline style — and its useful to know how we can modify it directly with JavaScript! Let’s demo this with the following HTML:

<!DOCTYPE html>
<html lang="en">
<body>
<div style="height: 200px;
width: 200px;
border: 5px solid black;
display: flex;
justify-content: center;
align-items: center;">Style me!</div>
</body>
</html>

Our initial output:

When working with CSS properties in the DOM, we use camelCase. So instead of using dashes as we would with CSS e.g.border-radius, we use camel case e.g. borderRadius. Where our first word is in lower case and any subsequent words are capitalized.

// Select the div
const div = document.querySelector('div');
// Make div into a circle, change color and font size
div.style.borderRadius = '50%';
div.style.backgroundColor = 'lightgreen';
div.style.fontSize = '30px';

Note: We could use setAttribute()to modify our styles eg. div.setAttribute('style', 'border-radius: 50%'); However, this will remove all existing inline styles. So it’s much better to use the style attribute directly.

Our output after adding these styles:

Of course, if we have multiple style changes to apply to an element, it’s best to apply them to a class in your CSS and just add the new class to the element via JavaScript 🆒.

Conclusion

And that’s it!! 🏆🏆🏆 We’ve worked with the DOM tree and nodes to learn all about accessing, traversing and modifying elements. If you’ve lasted this long — well done! You’re well on the way to mastering the DOM!

I hope you found this article useful! You can follow me on Medium. I’m also on Twitter. Feel free to leave any questions in the comments below. I’ll be glad to help out!

Thanks to Kiarash Irandoust

Timothy Robards

Written by

Web Developer. Follow me for weekly posts on all things front end! https://timothyrobards.com 🔥🔥🔥

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade