Simplified Understanding of Javascript DOM

Mohit
12 min readMay 6, 2022

I am at the heart of every web page. I am your Document Object Model.

What is the DOM?

DOM stands for Document Object Model. It is a programming interface that allows us to create, change, or remove elements from the document. We can also add events to these elements to make our page more dynamic.

The DOM views an HTML document as a tree of nodes. A node represents an HTML element.

Let’s take a look at this HTML code to better understand the DOM tree structure.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>DOM tree structure</title>
</head>
<body>
<h1>DOM tree structure</h1>
<h2>Learn about the DOM</h2>
</body>
</html>

Our document is called the root node and contains one child node which is the <html> element. The <html> element contains two children which are the <head> and <body> elements.

Both the <head> and <body> elements have children of their own.

Here is another way to visualize this tree of nodes.

Types of Nodes:

Using javascript you can get the node name and node type of any node:

  1. nodeName — The nodeName property returns the name of the types of node. For Example:
<!DOCTYPE html>
<html>
<body>
<p id="myP">Click the button to get the node type of this element.</p>
<button onclick="myFunction()">Try it</button><p id="demo"></p><script>
function myFunction() {
var x = document.getElementById("myP").nodeName;
console.log('nodeName value', x); // output will be p (p tag)
}
</script>
</body>
</html>

2. nodeType — The nodeType property returns an integer value where these integers indicate the type of node.

If the node is an element node, the nodeType property will return 1.

If the node is an attribute node, the nodeType property will return 2.

If the node is a text node, the nodeType property will return 3.

If the node is a comment node, the nodeType property will return 8.

<!DOCTYPE html>
<html>
<body>
<p id="myP">Click the button to get the node type of this element.</p>
<button onclick="myFunction()">Try it</button><p id="demo"></p><script>
function myFunction() {
var x = document.getElementById("myP").nodeType;
console.log('nodTYpe value', x); // output will be 1 (as this is an element node)
}
</script>
</body>
</html>

Now the Types of nodes include:

  1. Element Node: All the HTML Element Nodes are the Element nodes. Example -> <p>, <img>, <span> etc
  2. Text Node: The actual text inside an element is called a text node. Examples -> <p> This is plain text</p> . IN this the text inside the p tag is the Text Node.
  3. Comment Nodes: All the HTML comments are comment nodes. Example <-- This is an HTML comment -->.
  4. Attribute node: All attributes of an element are attribute nodes. Example class, title, style, etc

Different Ways to Access DOM:

  1. getElemetById(): We can access the dom element by getElementById() by providing the element with an id. Example:
<!DOCTYPE html>
<html>
<body>
<h1>The Document Object</h1>
<h2>The getElementById() Method</h2>
<p id="demo"></p><script>
const data = document.getElementById("demo");
console.log(data);
</script>
</body>
</html>
console.log will print : <p id="demo"></p>

2. getElementsByClassName(): We can access the dom element by getElementByClassName() by providing the element with a class name. Example:

<!DOCTYPE html>
<html>
<body>
<h1>The Document Object</h1>
<h2>The getElementsByClassName() Method</h2>
<p>Change the text of the first element with class="example":</p><div class="example">Element1</div>
<div class="example">Element2</div>
<script>
const collection = document.getElementsByClassName("example");
console.log(collection);
</script>
</body>
</html>
console.log will print : HTMLCollection(2) [div.example, div.example] // an array constaing all the elemnst whose class name is example.

3. getElementsByTagName(): We can access the dom element by getElementsByTagName() by tag name itself. Example:

<!DOCTYPE html>
<html>
<body>
<h1>The Document Object</h1>
<h2>The getElementsByTagName() Method</h2>
<p>An unordered list:</p>
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<p>The innerHTML of the second li element is:</p>
<p id="demo"></p>
<script>
const collection = document.getElementsByTagName("li");
console.log(collection);
</script>
</body>
</html>
console.log will print : HTMLCollection(3) [li, li, li] // will conatin all the three li elements

4. querySelector(): The querySelector() method returns the first element that matches a CSS selector. Example

<!DOCTYPE html>
<html>
<body>
<h1>The Document Object</h1>
<h2>The querySelector() Method</h2>
<h3>Add a background color to the first p element:</h3>
<p>This is a p element.</p>
<p>This is a p element.</p>
<script>
const query = document.querySelector("p");
console.log(query);
</script>
</body>
</html>
console.log will print :<p>This is a p element.</p> // this will return the first p tag

5. querySelectorAll(): The querySelectorAll() method returns all elements that matches a CSS selector(s). Example

<!DOCTYPE html>
<html>
<body>
<h1>The Document Object</h1>
<h2>The querySelectorAll() Method</h2>
<p>Add a background color all elements with class="example":</p>
<h2 class="example">A heading</h2>
<p class="example">A paragraph.</p>
<script>
const nodeList = document.querySelectorAll(".example");
console.log(nodeList);
</script>
</body>
</html>
console.log will print :NodeList(2) [h2.example, p.example] // this will have multiple elements that have exmaple as class

How the browser renders the HTML page

When a web page is loaded, the browser first reads the HTML text and constructs DOM Tree from it. Then it processes the CSS whether that is inline, embedded, or external CSS and constructs the CSSOM Tree from it. After these trees are constructed, then it constructs the Render-Tree from it. Lets go through them one by one:

DOM Tree: As already explained in the above section that the browser creates the Document Object Model. It is a tree of objects. Each node represents an HTML tag:

CSSOM Tree: After the browser had created the DOM tree in the previous step, it started creating the CSSOM. Stands for CSS Object Model. It is like the DOM but for CSS rules.CSSOM does not contain the document element which cannot be printed in screen example <head>, <meta> , <title> etc. So now the above DOM tree will become:

Most of the browsers have their own stylesheet which is User Agent Stylesheet, the browser first computes the final CSS properties of DOM by overriding User Agent Styles with the CSS provided by the developers and then constructs the node. If the developer pr the browser has not set the CSS, then its value is set to the default value of the property as specified by W3CSS Standard.

Render Tree: It is also a tree-like structure constructed by combining DOM and CSSOM together. The browser has to calculate the layout of each visible element and paint them on the screen.

As render Tree is a low-level representation of what will eventually get printed on the screen, it won’t contain nodes that do not hold any are in pixel matrix example : display: none as in pixel matrix it will represent as 0px 0px. Let's understand this by a diagram:

DOM + CSSOM = Render Tree

In the above diagram, the H2 tag is not visible in the render tree as it has displayed none.

There are some rendering sequences by which the tree gets rendered. Lets understand them briefly:

  1. Layout Operation: At first browser creates a layout of each individual Render tree node. The layout consists of the size of each node in pixels and where it will be printed on the screen.

2. Paint Operation: Creating layers help the browser efficiently perform painting operation throughout the life cycle of the web page such as scrolling or resizing the window. Now we have layers we can combine to draw them on the screen. But the browser does not draw all the layers in a single go.

Inside each layer, the browser fills the individual pixels for whatever visible property the element has such as border, background color, shadow, etc. This is called Rasterization.

3. Composition Operation: NOw in this, the layers that are formed until now are sent to GPU to finally draw it on the screen. Sending the entire layers to draw is clearly inefficient because this has to happen every time a reflow or repaint happens. Hence a layer is broken into different tiles which are then drawn on the screen.

Critical Rendering Path

What is the use/purpose of it??

By manipulating the DOM, you have infinite possibilities. You can create applications that update the data of the page without needing a refresh. Also, you can create applications that are customizable by the user and then change the layout of the page without a refresh. You can drag, move, and delete elements.

As I said, you have infinite possibilities — you just need to use your creativity.

  1. Document: Document interface describes the common properties and methods for any kind of document.
  2. Elements: All the tags that are inside your HTML or XML turn into a DOM element.
  3. Text: All the tags’ content.
  4. Attributes: All the attributes from a specific HTML element. In the image, the attribute class=”hero” is an attribute from the <p> element.

How to manipulate DOM?

Create custom events in JavaScript

A custom event can be created using the event constructor, like this:

const myEvent = new Event(‘myevent’, { bubbles: true, cancelable: true, composed: false})

We created the event myevent, by passing the event name to the Event constructor. Event names are case sensitive so we named them as myEvent and MyEvent.

a).bubbles

The bubbles property specifies whether the event should be propagated upward to the parent element or not.

If we set this to true it will get dispatched in a child element and the parent element can listen to the event and perform an action based on that. That’s the behavior of most DOM events and for custom events, it is set to false by default. In case we only want it to be dispatching a particular element we can stop the propagation of the event via event.stopPropagation().

b). cancelable

The name implies all of it, cancelable specifies whether the event should be cancelable.

Native DOM events are cancelable by default so we can call event.preventDeafult() on it which will prevent the default action of the event if the custom event had cancelable set to false, as calling the event.preventDeafult() will not perform any action.

c). composed

The composed property specifies whether the event should bubble across from the shadow (created when using the web components)to the real DOM.

Virtual DOM:

What is Virtual DOM ?

In simple words, virtual DOM is just a copy of the original DOM kept in the memory and synced with the real DOM by libraries such as ReactDOM. Virtual DOM has the same properties as the Real DOM, but it lacks the power to directly change the content of the screen.
Think of Virtual DOM as the blueprint of a machine, changes made to the blueprint don’t reflect on the machine itself.

Why do we need virtual Dom?

To understand why the concept of virtual DOM arose, let’s revisit the original DOM. As I mentioned, there are two parts to the DOM — the object-based representation of the HTML document and the API to manipulate that object.
For example, let’s take this simple HTML document with an unordered list and one list item.

<!doctype html>
<html lang="en">
<head></head>
<body>
<ul class="list">
<li class="list__item">List item</li>
</ul>
</body>
</html>

If we want to modify the content of the first list item to “List item one” and also add a second list item. To do this, we will need use the DOM APIs to find the elements we want to update, create the new elements, add attributes and content, then finally update the DOM elements themselves.

const listItemOne = document.getElementsByClassName(“list__item”)[0];
listItemOne.textContent = “List item one”;
const list = document.getElementsByClassName(“list”)[0];
const listItemTwo = document.createElement(“li”);
listItemTwo.classList.add(“list__item”);
listItemTwo.textContent = “List item two”;
list.appendChild(listItemTwo);

A virtual DOM can be thought of as a copy of the original DOM. This copy can be frequently manipulated and updated, without using the DOM APIs. Once all the updates have been made to the virtual DOM, we can look at what specific changes need to be made to the original DOM and make them in a targeted and optimized way.

const vdom = {tagName: "html",children: [{ tagName: "head" },{tagName: "body",children: [{tagName: "ul",attributes: { "class": "list" },children: [{tagName: "li",attributes: { "class": "list__item" },textContent: "List item"} // end li]} // end ul]} // end body]} // end html

we can use the virtual DOM to single out the specific changes that need to be made to the DOM and make those specific updates alone. Let’s go back to our unordered list example and make the same changes we did use the DOM API.
The first thing we would do is make a copy of the virtual DOM, containing the changes we want to make. Since we don’t need to use the DOM APIs, we can actually just create a new object altogether.

const copy = {
tagName: “ul”,
attributes: { “class”: “list” },
children: [
{
tagName: “li”,
attributes: { “class”: “list__item” },
textContent: “List item one”
},
{
tagName: “li”,
attributes: { “class”: “list__item” },
textContent: “List item two”
}
]
};

This copy is used to create what is called a “diff” between the original virtual DOM, in this case, the list, and the updated one.
A diff could look something like this:

const diffs = [
{
newNode: { /* new version of list item one */ },
oldNode: { /* original version of list item one */ },
index: /* index of element in parent’s list of child nodes */
},
{
newNode: { /* list item two */ },
index: { /* */ }
}
]

This diff provides instructions for how to update the actual DOM. Once all the diffs are collected, we can batch changes to the DOM, making only the updates that are needed.

What are the best practices to use it?

We should avoid manipulating the DOM. Some of the best practices are:

Avoid DOM Manipulation:

We can put a lot of styling code in our CSS instead of manipulating it directly with JavaScript.

For example, if we want to make an input field border be displayed as red when we click input submit.we can write the following HTML code:

<form>
<input type='text' required>
<button type='submit'>
Submit
</button>
</form>

and the javascript code as :

const input = document.querySelector('input');
const form = document.querySelector('form');
form.onsubmit = (e) => {
e.preventDefault();
}
input.oninvalid = () => {
input.style.borderColor = 'red';
input.style.borderStyle = 'solid';
input.style.borderWidth = '1px';
}

Instead of the above code, we can do it by CSS by making a class and calling the class name in the javascript code:

CSS:

.invalid {
border: 1px solid red;
}

javascript code:

const input = document.querySelector('input');
const form = document.querySelector('form');
form.onsubmit = (e) => {
e.preventDefault();
}
input.oninvalid = () => {
input.className = 'invalid';
}

Trim our HTML:

We can reduce the number of items that needed to be loaded by reducing the elements on our page.

Use document.getElementById()

We can use getElementById .

Getting things by ID is faster since there’s only one element with a given ID on a page. This means our browser doesn’t have to check all the nodes to find all the items.

For example, we can write:

const button = document.getElementById('window-minimize-button');

Use document.querySelector()

If we only want to get one element with the given selector, we can use querySelector to get the DOM node with the given selector.

The browser stops looking after the first node with the given selector is found, which makes the lookup faster.

For example, we can write:

const button = document.querySelector('#window-minimize-button');

Conclusion

You made it all the way until the end! Hope that this article helped you understand the Javascript DOM and how to use it to manipulate elements on your website.

We have covered these topics in this blog.

  1. What is the DOM?
  2. How the browser renders the HTML page?
  3. What is its use/purpose of it??
  4. Create custom events in JavaScript?
  5. What is Virtual DOM?
  6. What are the best practices to use it?

If you have found this useful, please consider recommending and sharing it with other fellow developers.

If you have any questions or feedback, let me know in the comments down below.

--

--