Skip to content

DOM

Selecting elements, handling events, and updating the page with the Document Object Model.

What you'll learn

  • What the DOM is and how the browser builds it from HTML
  • Selecting elements with querySelector and getElementById
  • Modifying content with textContent and innerHTML
  • Handling events with addEventListener
  • Creating and appending new elements

Concept

What Is the DOM?

The Document Object Model (DOM) is a live, tree-like representation of your HTML that JavaScript can read and modify. When the browser loads a page, it parses the HTML and builds this tree. Every HTML element becomes a node you can access via document.

document
  └── html
      ├── head
      │   └── title
      └── body
          ├── h1
          ├── p
          └── button

Selecting Elements

// By ID — returns a single element or null
const title = document.getElementById("main-title");

// By CSS selector — first match only
const button = document.querySelector(".btn-primary");

// All matches — returns a NodeList
const items = document.querySelectorAll("li");

querySelector and querySelectorAll accept any CSS selector, so they are the most flexible and are the modern default.

Modifying Content

const heading = document.querySelector("h1");
heading.textContent = "Updated Title"; // safe — sets plain text
heading.innerHTML = "<span>HTML</span>"; // parses HTML — XSS risk!

Prefer textContent when you only need plain text. innerHTML parses the string as HTML, which can introduce cross-site scripting (XSS) vulnerabilities if the content includes user input.

Handling Events

const button = document.querySelector("button");
button.addEventListener("click", (event) => {
  console.log("Clicked!", event.target);
});

Common events: click, input, change, submit, keydown, mouseover. The callback receives an event object with details about what happened.

Creating and Appending Elements

const list = document.querySelector("ul");
const newItem = document.createElement("li");
newItem.textContent = "A new item";
newItem.classList.add("highlight");
list.appendChild(newItem);

classList for Styling

const card = document.querySelector(".card");
card.classList.add("active");
card.classList.remove("hidden");
card.classList.toggle("selected"); // add if missing, remove if present

A Note on Frameworks

Modern apps often use React, Vue, or Svelte instead of touching the DOM directly. But understanding the DOM is essential — frameworks are abstractions over it, and you will still need it for browser extensions, vanilla scripts, and understanding how frameworks work under the hood.

Example

              // Select the button and the output area
const button = document.querySelector("#counter-btn");
const display = document.querySelector("#count-display");

let count = 0;

// Update the display
function updateDisplay() {
  display.textContent = `Count: ${count}`;
  // Toggle a CSS class based on the count
  display.classList.toggle("even", count % 2 === 0);
}

// Handle clicks
button.addEventListener("click", () => {
  count++;
  updateDisplay();

  // Dynamically create a log entry
  if (count <= 5) {
    const log = document.createElement("p");
    log.textContent = `Clicked ${count} time(s)`;
    document.querySelector("#log").appendChild(log);
  }
});

// Handle keyboard shortcuts
document.addEventListener("keydown", (e) => {
  if (e.key === "r") {
    count = 0;
    updateDisplay();
  }
});

updateDisplay(); // initialize
            

A working counter: selects elements, updates textContent safely, toggles a CSS class, creates and appends log entries, and listens for keyboard shortcuts. Paste this into a page with matching elements.

Try it

Common mistakes

The mistake

Using innerHTML with user input and creating an XSS vulnerability

The fix

Never put untrusted data into innerHTML. Use textContent for plain text, or sanitize the HTML first. Frameworks like React escape values by default for this reason.

The mistake

Calling querySelector before the element exists in the DOM

The fix

Put your script at the end of the body, or wrap it in DOMContentLoaded: document.addEventListener('DOMContentLoaded', () => { ... }). Otherwise querySelector returns null.

Related Snippets

Related Cheatsheets

Practice DOM

2 exercises

Practice DOM

Look up unfamiliar terms

A beginner-friendly glossary explains jargon in plain English — variables, functions, DOM, Promise, and more.

View glossary

Build real projects

Apply what you learned by building guided projects with starter code and solutions.

View projects

Decode error messages

Plain-English explanations of common errors — what they mean, why they happen, and how to fix them.

View errors