Topic 42 of 48 · Full Stack Essentials

JavaScript DOM

Lesson TL;DRTopic 5: JavaScript DOM 📖 14 min read · 🎯 intermediate · 🧭 Prerequisites: whileifconditionifelseelseif, arithmeticoperationswithwhileandifconditionsprimeoddeven Why this matters Up until now, your ...
14 min read·intermediate·javascript · dom · event-handling · dynamic-web

Topic 5: JavaScript DOM

📖 14 min read · 🎯 intermediate · 🧭 Prerequisites: while-if-condition-if-else-else-if, arithmetic-operations-with-while-and-if-conditions-prime-odd-even

Why this matters

Up until now, your web pages just sit there — you open them in a browser and they stare back at you. You can't click a button and see something change. You can't fill a form and watch the page respond. That feels broken, right? That's because HTML alone has no memory, no reactions, nothing. JavaScript fixes this through something called the DOM — the Document Object Model. It's how JavaScript reaches into your live page and changes text, swaps styles, adds new elements, or catches a button click — all without reloading the page. That's what we're learning today.

What You'll Learn

  • What the DOM is and how it represents an HTML document as a tree of nodes
  • How to access DOM elements using getElementById, getElementsByClassName, getElementsByTagName, querySelector, and querySelectorAll
  • How to modify element content, attributes, and CSS styles at runtime
  • How to create new elements and remove existing ones programmatically
  • How to attach and detach event listeners to make pages interactive
  • How to combine all of the above into a working interactive to-do list

The Analogy

Think of your HTML document as a city blueprint pinned to a wall. Every building, road, and park is drawn on it — but the blueprint itself can't change. The DOM is the live, three-dimensional model of that same city sitting on a table in front of the class. JavaScript is the class member who can pick up a building, paint it red, drop a new park in the middle of the square, or bulldoze an old structure — all while the city keeps running. When the model changes, every citizen browsing the city's website sees the update instantly, no reprint of the blueprint required.

Chapter 1: What Is the DOM?

The Document Object Model (DOM) is a programming interface for web documents. It represents a loaded HTML page so that programs — specifically JavaScript — can read and change the document's structure, style, and content at any time while the page is open in a browser.

The DOM represents the entire document as a tree of nodes. Each node in the tree corresponds to a part of the document:

  • The document node is the root.
  • Element nodes represent HTML tags (<body>, <div>, <p>, etc.).
  • Text nodes hold the text content inside elements.
  • Attribute nodes carry attribute values (id, class, href, etc.).
graph TD
  document --> html
  html --> head
  html --> body
  head --> title
  body --> h1
  body --> ul
  ul --> li1["li #1"]
  ul --> li2["li #2"]

Because every piece of the page is addressable as a node object, JavaScript can traverse this tree, find what it needs, and change it on the fly — which is how every modern interactive web page works.

Chapter 2: Accessing DOM Elements

Before you can change anything, you need a reference to the element. The document object exposes several methods for this.

getElementById

Returns the single element whose id attribute matches the given string. IDs must be unique per page, so this always returns one element (or null).

let element = document.getElementById("myElement");
console.log(element);

getElementsByClassName

Returns a live HTMLCollection of all elements that carry the specified class name. If the DOM changes after you call it, the collection updates automatically.

let elements = document.getElementsByClassName("myClass");
console.log(elements);

getElementsByTagName

Returns a live HTMLCollection of all elements with the given tag name across the entire document.

let elements = document.getElementsByTagName("p");
console.log(elements);

querySelector and querySelectorAll

These accept any valid CSS selector string, making them the most flexible option.

  • querySelector returns the first matching element.
  • querySelectorAll returns a static NodeList of all matching elements.
// First element with class "myClass"
let element = document.querySelector(".myClass");
console.log(element);

// All elements with class "myClass"
let elements = document.querySelectorAll(".myClass");
console.log(elements);

Use querySelector/querySelectorAll when you need selector power (e.g., "#form input[type='text']"). Use getElementById when you have a known ID and need the fastest possible lookup.

Chapter 3: Modifying DOM Elements

Once you hold a reference to an element, you can change its content, attributes, and styles in place.

Changing Content

Two properties let you overwrite what's inside an element:

  • textContent — sets or reads plain text; HTML tags are treated as literal characters (safe against XSS).
  • innerHTML — sets or reads raw HTML; the browser parses it, so you can inject tags (use carefully with untrusted input).
let element = document.getElementById("myElement");
element.textContent = "New content here!";

Changing Attributes

setAttribute(name, value) adds or overwrites an attribute on the element.

let element = document.getElementById("myElement");
element.setAttribute("class", "newClass");

You can read an attribute back with getAttribute("class"), and remove it with removeAttribute("class").

Changing Styles

The style property exposes the element's inline style declarations as a CSSStyleDeclaration object. CSS property names that contain hyphens are written in camelCase in JavaScript.

let element = document.getElementById("myElement");
element.style.color = "red";
element.style.backgroundColor = "yellow";

Setting element.style.color = "" (empty string) removes the inline override and lets stylesheet rules take back control.

Chapter 4: Creating and Removing DOM Elements

the trainer reminded the class that the DOM isn't read-only — you can build entirely new nodes and graft them onto the tree, or prune nodes you no longer need.

Creating Elements

  1. document.createElement(tagName) — creates a new element node (not yet attached to the page).
  2. Set its content and attributes.
  3. parentNode.appendChild(newElement) — inserts it as the last child of a parent.
let newElement = document.createElement("p");
newElement.textContent = "This is a new paragraph.";
document.body.appendChild(newElement);

appendChild always inserts at the end. To insert at a specific position use parentNode.insertBefore(newElement, referenceNode).

Removing Elements

parentNode.removeChild(child) detaches a child node from its parent and returns it (so you could re-attach it elsewhere if needed).

let element = document.getElementById("myElement");
element.parentNode.removeChild(element);

Modern browsers also support element.remove() as a shorthand — no parent reference required.

Chapter 5: Event Handling

A page that can only be read isn't useful enough. Events wire user actions — clicks, key presses, form submits, mouse movement — to JavaScript functions.

Adding Event Listeners

addEventListener(eventType, callback) registers a function to run when the specified event fires on the element.

let button = document.getElementById("myButton");
button.addEventListener("click", function() {
    alert("Button was clicked!");
});

Common event types: "click", "mouseover", "mouseout", "keydown", "keyup", "submit", "change", "input", "load".

Removing Event Listeners

To remove a listener, you must pass the same named function reference that was added. Anonymous inline functions cannot be removed this way.

function handleClick() {
    alert("Button was clicked!");
}

let button = document.getElementById("myButton");
button.addEventListener("click", handleClick);

// Later, when you no longer need it:
button.removeEventListener("click", handleClick);

This pattern is important for preventing memory leaks in long-lived pages — listeners that are never removed keep their callback (and everything it closes over) alive indefinitely.

Chapter 6: Putting It Together — Interactive To-Do List

The class's capstone exercise: a fully functional to-do list that uses every DOM skill covered so far. Clicking "Add Task" creates a new list item; clicking a task toggles it as completed.

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 = "";
});

Walk-through of what each part does:

  1. getElementById("addTaskButton").addEventListener("click", ...) — listens for the button click.
  2. taskInput.value — reads what the user typed into the text box.
  3. Empty-string guard — prevents blank tasks with an early return.
  4. document.createElement("li") — builds a new list-item node.
  5. taskItem.classList.toggle("completed") — each click on a task adds or removes the .completed class, applying the strikethrough style defined in CSS.
  6. appendChild — grafts the new item onto the <ul>.
  7. taskInput.value = "" — clears the input field ready for the next task.

🧪 Try It Yourself

Task: Extend the to-do list so each task has a "Delete" button that removes it from the list when clicked.

Steps:

  1. Inside the "click" listener for addTaskButton, after creating taskItem, create a <button> element with textContent = "Delete".
  2. Add a "click" listener on the delete button that calls taskItem.remove().
  3. Append the delete button to taskItem before appending taskItem to taskList.

Starter snippet:

let deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
deleteBtn.addEventListener("click", function() {
    taskItem.remove();
});
taskItem.appendChild(deleteBtn);

Success criterion: Type a task, click "Add Task" — the task appears with a "Delete" button. Clicking "Delete" removes that specific task. Clicking the task text still toggles the strikethrough. Open the browser console and confirm no errors appear.

🔍 Checkpoint Quiz

Q1. What does the DOM represent, and why does it matter for JavaScript?

A) A stylesheet that controls page colors B) A programming interface that models the HTML document as a tree of nodes, letting JavaScript read and modify structure, style, and content C) A server-side rendering engine that builds HTML before sending it to the browser D) A browser database for storing user preferences

Q2. Given the following snippet, what will console.log(elements) output?

let elements = document.getElementsByClassName("highlight");
console.log(elements);

A) The first <div> on the page B) undefined, because getElementsByClassName doesn't exist C) A live HTMLCollection of every element that has the class "highlight" D) A static array containing a snapshot of matching elements at call time

Q3. What is the bug in this code?

function handleResize() {
    console.log("resized!");
}
window.addEventListener("resize", handleResize);
window.removeEventListener("resize", function() {
    console.log("resized!");
});

A) removeEventListener is spelled incorrectly B) removeEventListener requires a named reference to the exact same function object that was added; passing a new anonymous function does nothing C) window does not support removeEventListener D) handleResize must be declared with const, not function

Q4. You have a <p id="status">Loading…</p>. A fetch call completes and you want to replace the text with "Data loaded!" without allowing any HTML injection. Which line is correct?

A) document.getElementById("status").innerHTML = "Data loaded!"; B) document.getElementById("status").textContent = "Data loaded!"; C) document.getElementById("status").setAttribute("text", "Data loaded!"); D) document.querySelector("status").value = "Data loaded!";

A1. B — The DOM is a programming interface that represents the document as a tree, giving JavaScript handles to every element, attribute, and text node on the page.

A2. C — getElementsByClassName returns a live HTMLCollection; it updates automatically if the DOM changes after the call. It is not a static array.

A3. B — removeEventListener matches listeners by function reference identity, not by source code equality. The anonymous function passed to removeEventListener is a brand-new object, so no listener is removed and handleResize stays registered.

A4. B — textContent sets plain text; the browser never parses it as HTML, so strings like <script> are rendered literally rather than executed. innerHTML would work but is unsafe with untrusted data.

🪞 Recap

  • The DOM is a live tree of nodes representing your HTML document; JavaScript can read and modify any node at any time.
  • Use getElementById, getElementsByClassName, getElementsByTagName, querySelector, and querySelectorAll to locate elements.
  • textContent, setAttribute, and the style property let you change content, attributes, and CSS without a page reload.
  • createElement + appendChild build new nodes; removeChild or element.remove() prune them.
  • addEventListener wires events to callbacks; always keep a named function reference if you plan to call removeEventListener later.

📚 Further Reading

Like this topic? It’s one of 48 in Full Stack Essentials.

Block your seat for ₹2,500 and join the next cohort.