Understanding and handling the DOM
The DOM is an extremely important concept in web development and, I venture to say, every one programming for the web (especially frontend developers) should know what it is and how it can be handled. And this is what this article is about. Have a good read!
What is the DOM?
In order to create a web page, the minimum you need is an HTML file. For, example, this is a very simple page:
<!DOCTYPE html>
<html>
<head>
<title>A very basic page</title>
</head>
<body>
<p>This is a very basic page.</p>
</body>
</html>
If you save the above code to an HTML file (e.g. index.html), and open it in a browser, this is what is rendered:
And if you inspect the page, this is what you will see:
Well, as you can see, it shows exactly the same markup from the HTML file that we’ve created.
Changing the page dynamically
Now, open your browser console and run the following code:
const newParagraph = document.createElement('p');
newParagraph.innerText = 'And this is a dynamically created paragraph';
document.body.appendChild(newParagraph);
If you did it, this is what you got:
And if you inspect the page again, two paragraphs are visible instead of just one:
This paragraph was created dynamically, by using JavaScript, and not by changing the original page source. When you inspect a page, you’re seeing its representation in memory and not its actual code. That’s what we call DOM (Document Object Model). In other words, when we request a given page in a browser, its source code is fetched, parsed and stored in memory. From that moment on, the original source is not needed anymore and that in-memory copy will be handled dynamically to achieve whatever the developer wants that page to do.
Libraries like React and frameworks such as Vue.js and Angular allow us to create complex web apps with hundreds of components, having an extremely simple HTML file that just “boots” the application. Practically all the work is done dynamically, with JavaScript. That means the DOM will be significantly different from its original HTML source in most part of modern web apps.
What are nodes?
The DOM is an hierarchical structure made of small parts called nodes. There are multiple types of nodes, here are some of them:
- Elements: paragraphs, divs, inputs, buttons, etc. (Type: Node.ELEMENT_NODE)
- Text: Every text within a document is a separate node. (Type: Node.TEXT_NODE)
- Attributes: Each attribute of an element is also a node. (Type: Node.ATTRIBUTE_NODE)
- Document: The document object itself is a node (Type: Node.DOCUMENT_NODE)
- Comments: Yes, even HTML comments are nodes. (Type: Node.COMMENT_NODE)
Since the DOM is structured as a tree, nodes such as document and elements can have children. These nodes that allow nesting have a children property, which is an HTMLCollection (a list that contains only elements). On the other hand, all nodes have a childNodes property, even those that don’t allow nesting (like comments). This property is a NodeList, which is a collection of nodes (and not only elements).
Handling the DOM
In the previous section, we dynamically created a paragraph and added it to the document. Now, let’s see other ways to query and change the DOM:
Finding an element by its ID
A simple way to retrieve an element by its ID is to use the document.getElementById method.
const menuEl = document.getElementById('main-menu');
Since the ID is meant to be unique, this method returns a single element or, if nothing is found, it returns null.
Finding elements by their name
In order to find elements by their name, you can use the document.getElementsByName method.
const ageInput = document.getElementsByName('age');
This method returns a NodeList.
Finding elements by a class name
In order to query the DOM for elements by their class name, use the document.getElementsByClassName method.
const cards = document.getElementsByClassName('card');
This method returns an HTMLCollection (a collection with only elements and no other type of nodes).
Finding elements by a tag name
It’s also possible to find all elements of a given type by using the document.getElementsByTagName method.
const headings = document.getElementsByTagName('h1');
This method returns an HTMLCollection.
Finding elements by… whatever =)
By using the document.querySelectorAll method, you can use any CSS selector to query the DOM:
const navLinks = document.querySelectorAll('#navbar li:not(:first-child) a');
const signUpInputs = document.querySelectorAll('#sign-up input');
const editButtons = document.querySelectorAll('[data-action="edit"]');
const menuEl = document.querySelectorAll('#main-menu');
const cards = document.querySelectorAll('.card');
This method returns a NodeList.
There is very a similar method called document.querySelector, which returns the first occurrence for a given selector and null, in case nothing is found.
Creating an element
As we saw in the first section, to create an element, you need to use the document.createElement method, supplying the tag name as argument.
const button = document.createElement('button');
It returns a reference to the created element. This element is not yet part of the DOM. We need to add it explicitly.
Adding an element to the document body or any other element
In order to add an element to the document body or another element, you just need to use the appendChild method:
document.body.appendChild(menu);
usersList.appendChild(newUser);
signUpForm.appendChild(companyNameInput);
Getting the value of an attribute
If you want to get the value of an element’s attribute, use the getAttribute method.
const action = button.getAttribute('data-action');
This method returns the value of the attribute or null, if it doesn’t exist.
Setting the value of an attribute
It’s equally easy to set the value of an attribute by using the setAttribute method.
button.setAttribute('data-action', 'edit');
Styling an element dynamically
The appearance of an element can also be easily controlled through the style property. It contains dozens of properties like display, backgroundColor, maxWidth, fontWeight and many others. Every aspect that is controllable by CSS can also be controlled this way:
productDetails.style.display = 'none';
menu.style.marginLeft = '10px';
backButton.style.borderStyle = 'solid';
As you might have noticed, these properties are camel cased. So, a CSS property like list-style-type becomes listStyleType and border-right-bottom would be borderRightBottom.
And what about the virtual DOM?
Changing the DOM can be an expensive operation sometimes. That’s why React uses an approach called “Virtual DOM”, that keeps an in-memory copy of the actual DOM and syncs the copy and original in a process called reconciliation. If you’re into React, check out this great article about the React VDOM.
Conclusion
- The DOM is an in-memory representation of a page source code.
- The DOM is made of small parts called nodes.
- There multiple types of nodes, including elements, attributes, text and comments.
- There are multiple ways to retrieve elements from the DOM. It’s even possible to use any valid CSS selector to execute a query.
- You can alter the DOM in multiple ways, adding nodes, changing attributes and styling elements.
Would you like to improve your programming skills and become a JavaScript expert? If so, I recommend you check out Mosh’s JavaScript course. And if you liked this article, share it with others as well!
Alcides, I am currently learning JavaScript and am finding your clear explanation of the DOM very helpful indeed. Thanks for this great article.