Topic 5: JavaScript DOM
📖 6 min read · 🎯 intermediate · 🧭 Prerequisites: form-buttons, javascript-bom
Why this matters
Up until now, you've been building pages that look good — but they sit still. A user clicks a button and nothing moves. A form submits and the page just reloads. That gap between "a design" and "a living interface" is where JavaScript and the DOM come in.
The DOM — Document Object Model — is the bridge. It's how JavaScript sees your HTML: not as text, but as a tree of live objects it can grab, change, or delete in real time. Once you understand the DOM, you stop building static screens and start building things that actually respond.
What You'll Learn
- Understand what the DOM is and how it represents an HTML document as a node tree
- Access DOM elements using
getElementById,getElementsByClassName,getElementsByTagName,querySelector, andquerySelectorAll - Modify element content, attributes, and inline styles at runtime
- Create new elements and remove existing ones programmatically
- Attach and detach event listeners to make pages interactive
- Build a working interactive to-do list that ties all techniques together
The Analogy
Think of a web page as a city's electrical grid. The HTML file is the blueprint — lines on paper showing where every light, switch, and outlet lives. The DOM is the live grid itself: actual wires carrying current, switches you can flip, bulbs you can swap out while the city is running. JavaScript is the electrician who walks the grid with a toolkit. She can read the meter on any circuit (getElementById), rewire a junction box (setAttribute), swap a bulb for a brighter one (textContent), or run a brand-new line to a section of the city that didn't exist in the original blueprint (createElement). None of those changes require shutting the city down — everything happens while residents go about their day.
Chapter 1: What Is the DOM?
The Document Object Model (DOM) is a programming interface for web documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as a tree of nodes, with each node representing part of the document.
graph TD
document --> html
html --> head
html --> body
head --> title
body --> h1
body --> ul
ul --> li1["li #task-1"]
ul --> li2["li #task-2"]
Every tag becomes an element node. Text inside a tag becomes a text node. Attributes live directly on their element node. Because it is a tree, every node knows its parent, its children, and its siblings — relationships JavaScript can traverse in any direction.
In short: the DOM is the bridge that lets JavaScript interact with HTML and CSS, making it possible to create dynamic, interactive web pages without ever reloading.
Chapter 2: Accessing DOM Elements
Before you can modify anything, you need a reference to it. The browser exposes several methods on the global document object.
getElementById
Returns the single element whose id attribute matches the given string.
let element = document.getElementById("myElement");
console.log(element);
getElementsByClassName
Returns a live HTMLCollection of all elements that carry the specified class name. Multiple elements can share a class, so you get a collection.
let elements = document.getElementsByClassName("myClass");
console.log(elements);
getElementsByTagName
Returns a live HTMLCollection of all elements with the given tag name.
let elements = document.getElementsByTagName("p");
console.log(elements);
querySelector and querySelectorAll
These accept any valid CSS selector — the most flexible option. querySelector returns the first match; querySelectorAll returns a static NodeList of all matches.
let element = document.querySelector(".myClass");
console.log(element);
let elements = document.querySelectorAll(".myClass");
console.log(elements);
| Method | Returns | Live? | Selector syntax |
|---|---|---|---|
getElementById | Single element | — | ID string |
getElementsByClassName | HTMLCollection | Yes | Class string |
getElementsByTagName | HTMLCollection | Yes | Tag string |
querySelector | Single element | No | CSS selector |
querySelectorAll | NodeList | No | CSS selector |
Chapter 3: Modifying DOM Elements
Once you hold a reference to an element, you can change its content, attributes, and styles.
Changing Content
Use textContent to set plain text (safe — no HTML parsing). Use innerHTML when you deliberately need to inject markup.
let element = document.getElementById("myElement");
element.textContent = "New content here!";
Changing Attributes
setAttribute accepts any attribute name and its new value.
let element = document.getElementById("myElement");
element.setAttribute("class", "newClass");
You can also read attributes with getAttribute("name") and remove them with removeAttribute("name").
Changing Styles
The style property maps to inline CSS. Each CSS property is written in camelCase.
let element = document.getElementById("myElement");
element.style.color = "red";
element.style.backgroundColor = "yellow";
For bulk style changes, prefer toggling a CSS class (via classList) over setting individual style properties — it keeps your CSS in one place and is easier to override.
Chapter 4: Creating and Removing DOM Elements
The DOM is not frozen at page load — you can add and delete nodes at any time.
Creating Elements
document.createElement makes a new element node (not yet in the page). Attach it to the live tree with appendChild or insertBefore.
let newElement = document.createElement("p");
newElement.textContent = "This is a new paragraph.";
document.body.appendChild(newElement);
Removing Elements
removeChild detaches a child node from its parent.
let element = document.getElementById("myElement");
element.parentNode.removeChild(element);
A modern shorthand — available in all current browsers — is calling element.remove() directly, without needing a reference to the parent.
Chapter 5: Event Handling
Static pages display information. Interactive pages respond to the user. Events are the mechanism: the browser fires a named event whenever something happens (a click, a keypress, a form submission), and your code listens for it.
Adding Event Listeners
addEventListener(type, handler) registers a function to run whenever the named event fires on that element.
let button = document.getElementById("myButton");
button.addEventListener("click", function() {
alert("Button was clicked!");
});
Common event types: "click", "input", "change", "submit", "keydown", "mouseover", "load".
Removing Event Listeners
To remove a listener, you must pass the exact same function reference that was used to add it. Anonymous functions cannot be removed this way — always assign named functions when you intend to clean up.
function handleClick() {
alert("Button was clicked!");
}
let button = document.getElementById("myButton");
button.addEventListener("click", handleClick);
// Later — detach the same handler:
button.removeEventListener("click", handleClick);
Chapter 6: Putting It Together — Interactive To-Do List
The class's capstone example: a fully working interactive to-do list that exercises every technique covered above — element creation, content setting, event listening, and class toggling.
HTML (index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive To-Do List</title>
<style>
.completed {
text-decoration: line-through;
color: gray;
}
</style>
</head>
<body>
<h1>To-Do List</h1>
<input type="text" id="newTask" placeholder="Enter a new task">
<button id="addTaskButton">Add Task</button>
<ul id="taskList"></ul>
<script src="todo.js"></script>
</body>
</html>
JavaScript (todo.js)
document.getElementById("addTaskButton").addEventListener("click", function() {
let taskInput = document.getElementById("newTask");
let taskText = taskInput.value;
if (taskText === "") {
alert("Please enter a task.");
return;
}
let taskItem = document.createElement("li");
taskItem.textContent = taskText;
taskItem.addEventListener("click", function() {
taskItem.classList.toggle("completed");
});
document.getElementById("taskList").appendChild(taskItem);
taskInput.value = "";
});
What each line does:
- Listen for a click on the "Add Task" button.
- Read the current value of the
#newTaskinput. - Guard against empty submissions.
- Create a new
<li>element and set its text. - Attach a click listener to that
<li>— clicking it toggles the.completedclass (strike-through styling). - Append the new list item to
#taskList. - Clear the input field so the user can type the next task immediately.
sequenceDiagram
participant User
participant Button
participant JS as todo.js
participant DOM
User->>Button: click "Add Task"
Button->>JS: fires "click" event
JS->>DOM: createElement("li")
JS->>DOM: appendChild(taskItem) to #taskList
User->>DOM: click a task item
DOM->>JS: fires "click" on li
JS->>DOM: classList.toggle("completed")
🧪 Try It Yourself
Task: Extend the to-do list so each task item also has a Delete button that removes just that item from the list.
Success criterion: After adding three tasks and clicking a delete button on one of them, only two tasks remain in the list — no page reload required.
Starter snippet (paste this inside the taskItem.addEventListener("click", ...) block, after you create taskItem):
let deleteBtn = document.createElement("button");
deleteBtn.textContent = " ✕";
deleteBtn.addEventListener("click", function(event) {
event.stopPropagation(); // prevent toggling .completed at the same time
taskItem.parentNode.removeChild(taskItem);
});
taskItem.appendChild(deleteBtn);
🔍 Checkpoint Quiz
Q1. The DOM represents an HTML document as what kind of data structure?
A) A flat array of elements
B) A key-value map of IDs to tags
C) A tree of nodes
D) A doubly-linked list of sibling elements
Q2. Given this snippet, what is logged to the console?
let items = document.querySelectorAll(".card");
console.log(items.length);
Assume the page has exactly three elements with class card.
A) "NodeList"
B) 3
C) undefined
D) A live HTMLCollection
Q3. What is the bug in the following code?
function onResize() { console.log("resized"); }
window.addEventListener("resize", onResize);
window.removeEventListener("resize", function() { console.log("resized"); });
A) removeEventListener is not a valid method on window
B) removeEventListener receives a different function reference than the one added, so the listener is never removed
C) The event name "resize" is not a real browser event
D) There is no bug
Q4. You want to add a new <section> element directly before an existing <footer> inside document.body. Which DOM method would you use?
A) appendChild
B) insertBefore
C) setAttribute
D) createElement alone (no insertion method needed)
A1. C — The DOM models the document as a tree of nodes; every tag, text run, and attribute is a node with parent/child relationships.
A2. B — querySelectorAll returns a static NodeList; .length on a NodeList with three matches is 3.
A3. B — removeEventListener must receive the exact same function reference that was passed to addEventListener. An anonymous function that happens to have identical source text is still a different object in memory, so it doesn't match and the listener remains attached.
A4. B — parentNode.insertBefore(newSection, footer) inserts newSection immediately before footer in the DOM tree. createElement only creates the node; a separate insertion call is always required.
🪞 Recap
- The DOM is a live, tree-shaped programming interface that lets JavaScript read and rewrite any part of a loaded HTML document.
- Five selector methods —
getElementById,getElementsByClassName,getElementsByTagName,querySelector,querySelectorAll— give you references to existing elements. textContent,setAttribute, and thestyleproperty let you change content, attributes, and inline styles on any element reference.createElement+appendChildadds new nodes;removeChild(orelement.remove()) deletes them.addEventListenerandremoveEventListenerwire up and tear down event-driven behavior; always use named functions when you need to remove a listener later.
📚 Further Reading
- MDN — Introduction to the DOM — the authoritative reference for every DOM interface
- MDN — EventTarget.addEventListener — full parameter list, options object (
once,capture,passive), and browser compatibility - javascript.info — Document — step-by-step walkthrough of DOM access, traversal, and modification with live examples
- ⬅️ Previous: JavaScript BOM
- ➡️ Next: Table, Forms & Page Layout Introduction