Welcome back! In Part 1, we established the "why"—we learned that Web APIs are the browser's built-in superpowers that let our JavaScript code interact with the world.
Today, we get our hands dirty with the most foundational and frequently used Web API of all: the Document Object Model, or the DOM.
Every time you see a web page change without a full reload—a pop-up modal, an item added to a cart, a "like" button turning red—you're seeing the DOM API in action. It’s the magic that transforms a static document into a living, breathing application.
What is the DOM?
When a browser loads an HTML file, it doesn't just see a block of text. It builds a live, interactive model of that text in memory. This model is called the Document Object Model. It represents the page as a tree of objects, where each HTML tag is a "node" in the tree.
The DOM API is your set of tools to interact with this tree. It lets you find any node, change it, add new ones, or remove old ones. In short, it’s how you control the page.
Let's master the four essential actions of DOM manipulation using modern JavaScript.
1. Finding Things: Querying the DOM
Before you can change something, you have to find it. You may have seen older code use methods like getElementById()
or getElementsByTagName()
. They work, but there's a more powerful and unified way.
Meet your new best friends: querySelector()
and querySelectorAll()
. They use CSS selectors—the same syntax you use in your stylesheets—to find elements.
To find the first matching element: document.querySelector()
// Finds the first element with the class 'intro-paragraph'
const intro = document.querySelector('.intro-paragraph');
// Finds the element with the ID 'main-image'
const mainImage = document.querySelector('#main-image');
// Finds the first button inside a form with the ID 'login-form'
const submitButton = document.querySelector('#login-form button');
To find all matching elements: document.querySelectorAll()
This returns a NodeList
, which is like an array. You can loop over it with forEach
.
// Finds ALL list items inside a <ul> with the class 'task-list'
const allTasks = document.querySelectorAll('.task-list li');
allTasks.forEach(task => {
console.log('Found a task:', task.textContent);
});
Why this is better: You only need to know one thing: CSS selectors. It's flexible, powerful, and consistent.
2. Changing Things: Modifying Elements
Once you've found an element, you can change almost anything about it.
Changing Text Content: element.textContent
This is the safe way to change the text inside an element. It doesn't interpret any HTML, which protects you from security risks.
const heading = document.querySelector('h1');
heading.textContent = 'Welcome to the World of the DOM!';
Security Warning: You might see
element.innerHTML
used. Be very careful!innerHTML
will parse and execute any HTML and script tags you pass to it, opening the door to Cross-Site Scripting (XSS) attacks. Only useinnerHTML
with content you completely trust. For user-generated content, always stick totextContent
.
Changing Styles (The Right Way): element.classList
You can change styles directly with element.style.color = 'red'
, but this mixes your CSS logic into your JavaScript. A much cleaner approach is to use CSS classes.
/* in your style.css */
.is-active {
background-color: #007bff;
color: white;
}
.is-hidden {
display: none;
}
// in your script.js
const myButton = document.querySelector('#my-button');
const myPanel = document.querySelector('#my-panel');
// Add a class
myButton.classList.add('is-active');
// Remove a class
myPanel.classList.remove('is-hidden');
// Toggle a class (add if it's not there, remove if it is)
myButton.classList.toggle('is-active');
Changing Attributes: element.setAttribute()
This is for changing attributes like src
on an image, href
on a link, or disabled
on a button.
const profilePic = document.querySelector('#profile-pic');
profilePic.setAttribute('src', '/images/new-avatar.png');
const submitBtn = document.querySelector('#submit');
submitBtn.setAttribute('disabled', 'true');
3. Creating and Removing Things
What about content that doesn't exist when the page loads?
Creating an element: document.createElement()
Adding it to the page: element.append()
The append()
method is a modern and convenient way to add one or more elements (or even text) to the end of a parent element.
// 1. Find the parent where we'll add our new element
const list = document.querySelector('.task-list');
// 2. Create the new element in memory
const newItem = document.createElement('li');
// 3. Configure it (using the methods we just learned!)
newItem.textContent = 'Write a blog post about the DOM';
newItem.classList.add('task');
// 4. Add it to the page!
list.append(newItem);
Removing an element: element.remove()
This one is beautifully simple.
const thingToRemove = document.querySelector('#old-banner');
thingToRemove.remove();
4. Responding to the User: Event Listeners
This is the key to interactivity. We need to run our code when the user does something, like click a button or submit a form.
The addEventListener()
method is our tool for this. It "listens" for a specific event on an element and runs a function when it happens.
const themeToggleButton = document.querySelector('#theme-toggle');
// The function to run when the event happens
function handleThemeToggle() {
document.body.classList.toggle('dark-mode');
console.log('Theme was toggled!');
}
// Attach the listener
themeToggleButton.addEventListener('click', handleThemeToggle);
A common use case is handling form submissions. By default, submitting a form reloads the page. We can prevent this with event.preventDefault()
.
const myForm = document.querySelector('#my-form');
myForm.addEventListener('submit', function(event) {
// Stop the default browser action (page reload)
event.preventDefault();
console.log('Form submitted without reloading!');
// Now you can grab form data and do something with it.
});
Mini-Project: A Simple To-Do List
Let's put it all together! This simple to-do list uses every concept we've covered.
HTML (index.html
):
<h1>My To-Do List</h1>
<form id="todo-form">
<input type="text" id="todo-input" placeholder="Add a new task..." required />
<button type="submit">Add</button>
</form>
<ul id="todo-list"></ul>
JavaScript (script.js
):
// 1. Find the key elements
const form = document.querySelector('#todo-form');
const input = document.querySelector('#todo-input');
const list = document.querySelector('#todo-list');
// 2. Listen for the form submission
form.addEventListener('submit', function(event) {
// Prevent the page from reloading
event.preventDefault();
// Get the text from the input field
const taskText = input.value;
// 3. Create a new list item
const newTask = document.createElement('li');
newTask.textContent = taskText;
// 4. Add the new item to the list
list.append(newTask);
// Clear the input field for the next task
input.value = '';
});
And just like that, you have a functional, interactive application using nothing but the browser's own DOM API.
What's Next?
You now hold the keys to the kingdom. You can find, change, create, and react to anything on a web page. This skill is the absolute foundation of front-end development. Understanding how frameworks like React and Vue do this under the hood will make you a much stronger developer.
But our page is still lonely. It can't fetch data from a server or remember our to-do list if we close the tab.
In Part 3, we'll give our browser a backpack by exploring the Fetch API to get data from the outside world and the Web Storage API to remember it.
Top comments (0)