Mastering DOM Manipulation with Vanilla JavaScript
The Document Object Model, or DOM for short, is a fundamental concept in web development. It‘s a programming interface that allows you to interact with and modify the content, structure and style of a web page dynamically using JavaScript.
Essentially, the DOM represents an HTML document as a tree-like structure where each element, attribute and piece of text becomes a node in the tree. JavaScript provides a rich set of methods and properties to traverse and manipulate the DOM tree. Learning these DOM APIs is a core skill for any front-end developer.
In this post, we‘ll explore the most essential concepts and techniques for DOM manipulation using plain JavaScript. While frameworks like React and Vue provide abstractions over the DOM, having a solid grasp of the underlying APIs is still very valuable. Let‘s dive in!
Accessing Elements
The starting point of DOM manipulation is getting access to the elements you want to work with. There are a number of ways to do this:
Accessing Individual Elements
To retrieve a single element, you can use:
document.getElementById(id)
– selects an element by its unique id attributedocument.querySelector(selector)
– selects the first element that matches a given CSS selector
For example:
// Select the element with id ‘header‘
const header = document.getElementById(‘header‘);
// Select the first <p> element inside a <div>
const paragraph = document.querySelector(‘div p‘);
Accessing Multiple Elements
To retrieve collections of elements, you can use:
document.getElementsByClassName(className)
– selects all elements with the given class namedocument.getElementsByTagName(tagName)
– selects all elements with the given tag namedocument.querySelectorAll(selector)
– selects all elements that match a given CSS selector
For example:
// Select all elements with class ‘highlight‘
const highlights = document.getElementsByClassName(‘highlight‘);
// Select all <li> elements
const listItems = document.getElementsByTagName(‘li‘);
// Select all <p> elements inside a <div>
const paragraphs = document.querySelectorAll(‘div p‘);
Note that getElementsByClassName
and getElementsByTagName
return "live" node lists that automatically update if the DOM changes. querySelectorAll
returns a "static" node list that doesn‘t reflect subsequent changes.
Traversing the DOM Tree
Once you have a reference to an element, you can move around the DOM tree using these properties:
node.firstChild
– access the first child nodenode.lastChild
– access the last child nodenode.parentNode
– access the parent nodenode.nextSibling
– access the next sibling nodenode.previousSibling
– access the previous sibling node
const list = document.querySelector(‘ul‘);
// Access first child
const firstItem = list.firstChild;
// Access parent
const parent = list.parentNode;
// Access next sibling
const nextElement = list.nextSibling;
These properties allow you to navigate the DOM horizontally (siblings) and vertically (parents and children). Note that whitespace between elements is considered a text node, so these properties may return nodes of type text instead of actual elements.
Manipulating Element Content
There are several ways to get and set the content of an element.
Text Content
To work with plain text content, you can use:
node.textContent
– gets or sets the text content of an element and all its descendantsnode.innerText
– similar to textContent but more aware of styling and only returns "human-readable" elements
const paragraph = document.querySelector(‘p‘);
// Read text content
console.log(paragraph.textContent);
// Modify text content
paragraph.textContent = ‘New text content‘;
HTML Content
To work with HTML content, you use:
node.innerHTML
– gets or sets the HTML content inside an element
// Replace content of a <div> with a new <p>
div.innerHTML = ‘<p>New paragraph content</p>‘;
Be careful with innerHTML, as it completely replaces the current content. It‘s also a security risk if you‘re inserting untrusted content that may contain XSS attacks.
A safer way to create and insert elements is:
document.createElement(tagName)
– creates a new element with the given tag nameparentNode.appendChild(child)
– appends a new child node to a parentparentNode.insertBefore(newNode, referenceNode)
– inserts a new node before a reference node
// Create a new <li> element
const li = document.createElement(‘li‘);
li.textContent = ‘New list item‘;
// Insert into a <ul>
const ul = document.querySelector(‘ul‘);
ul.appendChild(li);
To remove elements, you use:
parentNode.removeChild(child)
– removes a child node from its parent
const li = document.querySelector(‘li‘);
const ul = li.parentNode;
ul.removeChild(li);
Working with Attributes
To get, set, check and remove element attributes, you can use:
element.getAttribute(name)
– gets the value of an attributeelement.setAttribute(name, value)
– sets the value of an attributeelement.hasAttribute(name)
– checks if an attribute existselement.removeAttribute(name)
– removes an attribute
const link = document.querySelector(‘a‘);
// Get href attribute
console.log(link.getAttribute(‘href‘));
// Add target attribute
link.setAttribute(‘target‘, ‘_blank‘);
// Check if title attribute exists
if (link.hasAttribute(‘title‘)) {...}
// Remove title attribute
link.removeAttribute(‘title‘);
Two attributes that are commonly accessed and modified are id and class:
element.id
– gets or sets the id of an elementelement.className
– gets or sets the class attribute of an elementelement.classList
– helpful methods to add, remove and toggle CSS classes
const div = document.querySelector(‘div‘);
// Add an id
div.id = ‘content‘;
// Add a class
div.className = ‘highlight‘;
// Toggle a class
div.classList.toggle(‘visible‘);
Advanced Topics
We‘ve covered the most essential concepts of DOM manipulation, but there‘s a lot more to explore:
- Event handling – how to listen for and respond to events like clicks, keypresses, form submission etc.
- Styles – getting and setting inline styles using the style property
- Forms – accessing form fields and their values, form validation
- Animation – creating animations and transitions using CSS and JavaScript
- Performance – best practices to minimize repaints and reflows when manipulating the DOM
Some other topics related to the DOM worth exploring are:
-
The difference between the DOM (Document Object Model) and BOM (Browser Object Model) which includes objects like window, screen, location, history etc.
-
How JavaScript frameworks like React and Vue abstract away low-level DOM operations and provide a declarative way to describe UIs as a function of state.
-
Emerging web standards like Web Components and the Shadow DOM that aim to provide stronger encapsulation and reusability of DOM elements.
Conclusion
We‘ve taken a whirlwind tour of the most essential DOM manipulation concepts and techniques using vanilla JavaScript. I hope this post has given you a solid foundation to start working with the DOM in your projects.
Remember that while frameworks abstract a lot of DOM manipulation complexity, having an understanding of the underlying web platform is still incredibly valuable. Don‘t be afraid to peek under the hood of your favorite framework and see how it works its magic!
Happy coding!