I started sharing what I learnt from a Vanilla JS course in this blogpost, this article is a continuation of that post, a part 2 if you will.
In the previous article, we explored in full details what the DOM is, how to select elements from it using various methods such as by id, name, classname and also via CSS Selectors. You should check it out to get up to speed about elements selection.
In this article we'd explore what to do with the elements selected, but first, let's uncover some fascinating facts about the DOM that might change how you think about it entirely.
DOM FACTS: The Hidden Truth
The HTML file and the DOM aren't the exact same thing. This is crucial to understand - they're related but separate entities.
Here's something that might surprise you: try creating an HTML file with just
<h1>Hello World</h1>
and nothing else. When you open it in a browser and inspect the DOM, you'll find<head>
,<body>
, and<html>
tags that you never wrote. The browser silently adds these essential elements behind the scenes.The above goes to show that the
<head>
and the<body>
tags can be implicit in an HTML file, but they're compulsory for the DOM.The DOM is alive, your HTML file is static. If JavaScript changes the DOM (adding elements, changing text), those changes only exist in memory. Hit "view source" and you'll see your original HTML unchanged. This is why developers use browser dev tools instead of "view source" when debugging.
It's why the "view source" (which shows the exact html file) and inspecting in the browser (which typically includes the extra things the DOM adds) are different.
The DOM treats everything as nodes - not just elements. Comments, text, even the whitespace between tags are all separate nodes with their own properties and methods.
Whitespace is invisible but real. That space between
<div>One</div>
<div>Two</div>
becomes an actual text node in the DOM. This is why sometimes you get unexpected spacing or whyelement.firstChild
returns a text node instead of the element you expected.Browsers are HTML fixers, not rule enforcers. The DOM doesn't just parse your HTML - it actively repairs it:
Unclosed tags get auto-closed
Invalid nesting gets re-arranged (like putting a
<div>
inside a<p>
)Missing attributes get default values
Malformed tables get restructured with proper
<tbody>
elements.
Element Manipulation: The Essentials
Most times, the reason for selecting elements in the DOM is to manipulate them. Here are the core methods:
1) Accessing and modifying text content:
Use textContent
(for plain text), innerText
(for visible text only), and innerHTML
(for HTML content). Each serves different purposes depending on whether you want to preserve formatting or include HTML tags.
// JavaScript
element.textContent = "Plain text - safe from XSS";
element.innerText = "Respects CSS styling and visibility";
element.innerHTML = "<strong>Can include HTML</strong> - use carefully";
2) Creating and Removing Elements:
Creating elements is like 3D printing for the web:
// JavaScript
const newDiv = document.createElement('div');
newDiv.textContent = 'I exist in memory but not on the page yet';
document.body.appendChild(newDiv); // Now it's born into the visible DOM
Removing elements has a quirk - you can't delete yourself:
// The modern way
element.remove();
// The traditional way (still widely used)
element.parentNode.removeChild(element);
3) Adding Event Listeners: Making the DOM Interactive
Events are how the DOM talks back to JavaScript. But here's what most tutorials don't tell you, there are different ways to bind events, and they behave very differently.
Two Ways to Bind Events
1) Event Properties - The Simple But Limited Way
element.onclick = function() {
console.log('First handler');
};
element.onclick = function() {
console.log('Second handler - this overwrites the first!');
};
// Only "Second handler" will run
The problem with this method is that it's just a property assignment. Like any object property, setting it twice overwrites the previous value. It uses the getter/setter pattern under the hood, you're literally replacing the function stored in the onclick
property.
2) addEventListener - The Powerful Approach
element.addEventListener('click', function() {
console.log('First handler');
});
element.addEventListener('click', function() {
console.log('Second handler');
});
// Both handlers will run
This method uses the observer design pattern, it maintains a list of functions to call when the event happens. You can add as many listeners as you want, and they'll all execute.
addEventListener's Hidden Powers
The third parameter unlocks advanced behavior:
element.addEventListener('click', handler, {
once: true, // Run only once, then auto-remove
passive: true, // Promise not to call preventDefault() - performance boost
capture: true // Listen during capture phase instead of bubble phase
});
Event bubbling quirk: Click a button inside a div, and the div's click event fires too by default. This "bubbling up" happens unless you call event.stopPropagation()
or use the capture
option to listen during the downward journey instead.
Pro tip: Always use addEventListener
in real projects. Event properties are mainly useful for quick prototypes or when you specifically want to ensure only one handler exists.
4) DOM Traversal: Family Navigation
The DOM's family tree structure means every element has relatives:
element.parentNode // Go up one level
element.children // All child elements
element.nextElementSibling // Next brother/sister
element.previousElementSibling // Previous sibling
Pro tip: children
gives you elements only, while childNodes
includes text nodes (like whitespace), which usually isn't what you want.
Wrapping Up
Understanding the DOM goes beyond just knowing how to select and manipulate elements. The real power comes from understanding what's happening behind the scenes, how browsers transform your HTML into a living document tree, why whitespace matters, and how events flow through this structure.
These insights will help you debug issues faster, write more efficient code, and understand why certain DOM behaviors seem "weird" at first glance. The DOM isn't just a programming interface it's a fascinating system that bridges the gap between static markup and dynamic web applications.
In the next article, we'll dive deeper into advanced DOM concepts like performance optimization and working with large element collections. Until then, experiment with these concepts and see how they change your perspective on web development.
You can always reach out on Twitter
Top comments (0)