Chapter 5: The Document Object Model (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 nodes and objects, allowing JavaScript to interact with the page.
- Global DOM objects (window, document, location, navigator, screen, history)
- Unobtrusive JavaScript and best practices
- Modifying element content, styles, and classes
- Traversing and manipulating the DOM tree
- Using browser DevTools for debugging
5.1 Global DOM Objects
When JavaScript runs in a browser, it has access to several global objects that represent different aspects of the browser environment. These objects provide the foundation for all DOM manipulation and browser interaction.
The Six Global DOM Objects
Every browser provides six core global objects that JavaScript can access:
| Object | Description | Common Uses |
|---|---|---|
window |
The browser window itself; the global scope | Timers, alerts, window dimensions |
document |
The HTML document loaded in the window | Selecting/modifying elements |
location |
The current URL and navigation | Redirects, URL parameters |
navigator |
Information about the browser | Browser detection, geolocation |
screen |
Information about the user's screen | Screen dimensions, color depth |
history |
The browser's session history | Back/forward navigation |
The window Object
The window object is the top-level object in the browser. All global variables
and functions become properties of window.
// Window properties
console.log(window.innerWidth); // Browser viewport width
console.log(window.innerHeight); // Browser viewport height
console.log(window.outerWidth); // Full window width
console.log(window.outerHeight); // Full window height
// Window methods
window.alert("Hello!"); // Show alert dialog
window.confirm("Sure?"); // Show confirm dialog (returns boolean)
window.prompt("Name?"); // Show input dialog (returns string)
// Timers
window.setTimeout(() => console.log("Delayed!"), 1000);
window.setInterval(() => console.log("Repeating!"), 2000);
The document Object
The document object represents the entire HTML page. It's your primary interface
for selecting and manipulating DOM elements.
// Document properties
console.log(document.title); // Page title
console.log(document.URL); // Current URL
console.log(document.referrer); // Previous page URL
console.log(document.cookie); // Cookies (string)
// Selecting elements
document.getElementById("myId"); // By ID
document.querySelector(".myClass"); // CSS selector (first match)
document.querySelectorAll("p"); // All matches
// Document structure
console.log(document.documentElement); // <html> element
console.log(document.head); // <head> element
console.log(document.body); // <body> element
The location Object
The location object provides information about the current URL and methods to
navigate to other pages.
// Location properties (for URL: https://example.com:8080/path/page.html?id=123#section)
console.log(location.href); // Full URL
console.log(location.protocol); // "https:"
console.log(location.host); // "example.com:8080"
console.log(location.hostname); // "example.com"
console.log(location.port); // "8080"
console.log(location.pathname); // "/path/page.html"
console.log(location.search); // "?id=123"
console.log(location.hash); // "#section"
// Navigation methods
location.assign("https://google.com"); // Navigate (adds to history)
location.replace("https://google.com"); // Navigate (no history entry)
location.reload(); // Refresh the page
The navigator, screen, and history Objects
// Navigator - browser information
console.log(navigator.userAgent); // Browser identifier string
console.log(navigator.language); // Browser language (e.g., "en-US")
console.log(navigator.onLine); // true if connected to internet
console.log(navigator.cookieEnabled); // true if cookies enabled
// Screen - display information
console.log(screen.width); // Screen width in pixels
console.log(screen.height); // Screen height in pixels
console.log(screen.availWidth); // Available width (minus taskbar)
console.log(screen.colorDepth); // Color depth (bits)
// History - session navigation
history.back(); // Go back one page
history.forward(); // Go forward one page
history.go(-2); // Go back 2 pages
console.log(history.length); // Number of entries in history
5.1.2 Unobtrusive JavaScript
Unobtrusive JavaScript is a best practice that keeps JavaScript code separate from HTML, making code more maintainable and accessible. Instead of inline event handlers, we attach events from external JavaScript files.
<button onclick="alert('Clicked!')">Click Me</button>
<a href="#" onclick="doSomething(); return false;">Link</a>
<input onchange="validateField(this)">
Problems: Mixes behavior with structure, hard to maintain, not accessible.
<button id="myButton">Click Me</button>
<a href="/actual-page" id="myLink">Link</a>
<input id="myInput">
document.getElementById("myButton").onclick = function() {
alert("Clicked!");
};
document.getElementById("myLink").onclick = function(event) {
event.preventDefault();
doSomething();
};
The window.onload Event Handler
When JavaScript runs, the DOM might not be fully loaded yet. The window.onload
event fires when the entire page (including images, stylesheets) has loaded.
// Wait for page to fully load before running code
window.onload = function() {
// DOM is now fully loaded - safe to manipulate elements
const heading = document.getElementById("main-heading");
heading.textContent = "Page Loaded!";
};
// Modern alternative: DOMContentLoaded (faster, doesn't wait for images)
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM ready!");
});
Anonymous Functions
An anonymous function is a function without a name. They're commonly used for event handlers and callbacks.
// Named function
function greet() {
console.log("Hello!");
}
// Anonymous function (assigned to variable)
const greet = function() {
console.log("Hello!");
};
// Anonymous function (as event handler)
button.onclick = function() {
console.log("Clicked!");
};
// Arrow function (ES6 shorthand)
button.onclick = () => console.log("Clicked!");
// With parameters
button.onclick = (event) => {
console.log(event.target);
};
The this Keyword in DOM Events
In event handlers, this refers to the DOM element that triggered the event.
This is incredibly useful for reusable event handlers.
// 'this' refers to the clicked button
const buttons = document.querySelectorAll(".btn");
buttons.forEach(function(button) {
button.onclick = function() {
console.log(this.textContent); // Text of THIS button
this.style.backgroundColor = "green";
};
});
// ⚠️ Warning: Arrow functions don't bind 'this'!
button.onclick = () => {
console.log(this); // 'this' is NOT the button (inherits from scope)
};
// Solution: Use event.target with arrow functions
button.onclick = (event) => {
console.log(event.target); // The clicked element
};
5.2 DOM Element Objects
Once you've selected a DOM element, you can read and modify its properties. This section covers the most common ways to manipulate element content, styles, and attributes.
Modifying Element Text
There are three main properties for working with element content:
| Property | Description | When to Use |
|---|---|---|
innerHTML |
Gets/sets HTML content (parses tags) | When you need to insert HTML elements |
textContent |
Gets/sets text only (ignores tags) | When inserting plain text (safer!) |
value |
Gets/sets value of form inputs | For <input>, <textarea>, <select> |
const div = document.getElementById("myDiv");
const input = document.getElementById("myInput");
// innerHTML - parses HTML tags
div.innerHTML = "<strong>Bold text</strong>"; // Renders as bold
console.log(div.innerHTML); // "<strong>Bold text</strong>"
// textContent - treats everything as text (safer)
div.textContent = "<strong>Bold text</strong>"; // Shows literal tags
console.log(div.textContent); // "<strong>Bold text</strong>"
// value - for form elements
console.log(input.value); // Current input value
input.value = "New text"; // Set new value
input.value = ""; // Clear the input
Never use innerHTML with user-provided data! It can lead to Cross-Site
Scripting (XSS) attacks where malicious code is injected into your page.
// ❌ DANGEROUS - user could inject scripts
div.innerHTML = userInput;
// ✅ SAFE - textContent escapes HTML
div.textContent = userInput;
Adjusting Styles with the DOM
Every element has a style property that allows you to directly modify CSS
properties. Note that CSS properties with hyphens become camelCase in JavaScript.
const element = document.getElementById("myElement");
// Setting individual styles
element.style.color = "blue";
element.style.backgroundColor = "yellow"; // Note: camelCase!
element.style.fontSize = "20px";
element.style.border = "2px solid red";
element.style.marginTop = "10px";
// Reading styles (only works for inline styles)
console.log(element.style.color); // "blue"
// To read computed styles (including CSS file styles)
const computed = window.getComputedStyle(element);
console.log(computed.fontSize); // "20px"
CSS Property Name Conversion
| CSS Property | JavaScript Property |
|---|---|
background-color |
backgroundColor |
font-size |
fontSize |
margin-top |
marginTop |
border-radius |
borderRadius |
z-index |
zIndex |
Unobtrusive Styling with className and classList
Instead of setting styles directly, the unobtrusive approach is to toggle CSS classes. This keeps your styles in CSS files and your JavaScript clean.
const element = document.getElementById("myElement");
// className - get/set the entire class attribute
console.log(element.className); // "card primary"
element.className = "card active"; // Replaces ALL classes
// classList - modern API for managing classes (preferred!)
element.classList.add("active"); // Add a class
element.classList.remove("hidden"); // Remove a class
element.classList.toggle("expanded"); // Add if missing, remove if present
element.classList.contains("active"); // Returns true/false
element.classList.replace("old", "new"); // Replace one class with another
// Add multiple classes
element.classList.add("class1", "class2", "class3");
Define your visual states in CSS, then toggle classes in JavaScript:
.button { background: blue; }
.button.loading { background: gray; cursor: wait; }
.button.success { background: green; }
button.classList.add("loading");
// After async operation...
button.classList.remove("loading");
button.classList.add("success");
5.3 The DOM Tree
The DOM represents an HTML document as a tree structure where each element, attribute, and piece of text is a node. Understanding this tree structure is essential for navigating and manipulating the DOM.
Types of DOM Nodes
There are three main types of nodes you'll work with:
| Node Type | nodeType Value | Description | Example |
|---|---|---|---|
| Element Node | 1 | HTML tags | <div>, <p>, <span>
|
| Text Node | 3 | Text content inside elements | "Hello World" |
| Attribute Node | 2 | Attributes on elements | id="main", class="card" |
<div id="container">
<p class="intro">Hello <strong>World</strong></p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
const div = document.getElementById("container");
console.log(div.nodeType); // 1 (Element)
console.log(div.nodeName); // "DIV"
console.log(div.nodeValue); // null (elements have no nodeValue)
const textNode = div.firstChild;
console.log(textNode.nodeType); // 3 (Text - includes whitespace!)
Traversing the DOM Tree
You can navigate between nodes using these properties:
| Property | Returns | Includes Text Nodes? |
|---|---|---|
parentNode |
Parent node | N/A |
childNodes |
All child nodes (NodeList) | ✅ Yes |
children |
Child elements only | ❌ No |
firstChild |
First child node | ✅ Yes |
firstElementChild |
First child element | ❌ No |
lastChild |
Last child node | ✅ Yes |
lastElementChild |
Last child element | ❌ No |
nextSibling |
Next sibling node | ✅ Yes |
nextElementSibling |
Next sibling element | ❌ No |
previousSibling |
Previous sibling node | ✅ Yes |
previousElementSibling |
Previous sibling element | ❌ No |
Whitespace between tags creates text nodes! Use the Element variants
(like firstElementChild) to skip text nodes.
const ul = document.querySelector("ul");
// Parent navigation
console.log(ul.parentNode); // <div id="container">
// Child navigation (prefer Element variants)
console.log(ul.children); // HTMLCollection [li, li]
console.log(ul.firstElementChild); // First <li>
console.log(ul.lastElementChild); // Last <li>
// Sibling navigation
const firstLi = ul.firstElementChild;
console.log(firstLi.nextElementSibling); // Second <li>
Selecting Groups of Elements
Modern JavaScript provides powerful methods to select elements:
// By ID (returns single element or null)
const header = document.getElementById("header");
// By tag name (returns live HTMLCollection)
const paragraphs = document.getElementsByTagName("p");
// By class name (returns live HTMLCollection)
const cards = document.getElementsByClassName("card");
// By name attribute (returns live NodeList)
const radios = document.getElementsByName("color");
// CSS selectors (RECOMMENDED - most flexible)
const firstCard = document.querySelector(".card"); // First match
const allCards = document.querySelectorAll(".card"); // All matches
const nested = document.querySelector("#main .card.active"); // Complex selector
Creating and Modifying Nodes
You can dynamically create, insert, and remove DOM elements:
// Create a new element
const newDiv = document.createElement("div");
newDiv.id = "myNewDiv";
newDiv.className = "card";
newDiv.textContent = "I'm a new div!";
// Create a text node (rarely needed - textContent is easier)
const textNode = document.createTextNode("Hello!");
// Set attributes
newDiv.setAttribute("data-id", "123");
newDiv.setAttribute("aria-label", "Card");
console.log(newDiv.getAttribute("data-id")); // "123"
const container = document.getElementById("container");
const newItem = document.createElement("li");
newItem.textContent = "New Item";
// appendChild - adds to the end
container.appendChild(newItem);
// insertBefore - insert before a reference node
const referenceNode = container.firstElementChild;
container.insertBefore(newItem, referenceNode);
// Modern methods (easier syntax)
container.prepend(newItem); // Add to beginning
container.append(newItem); // Add to end
referenceNode.before(newItem); // Insert before
referenceNode.after(newItem); // Insert after
// Insert HTML string
container.insertAdjacentHTML("beforeend", "<p>New paragraph</p>");
const container = document.getElementById("container");
const oldChild = container.firstElementChild;
// removeChild - remove a child element (returns removed node)
const removed = container.removeChild(oldChild);
// Modern: remove() - element removes itself
oldChild.remove();
// replaceChild - replace one child with another
const newChild = document.createElement("p");
newChild.textContent = "Replacement!";
container.replaceChild(newChild, oldChild);
// Modern: replaceWith()
oldChild.replaceWith(newChild);
5.3.2 Browser DevTools for DOM Debugging
Modern browsers have powerful built-in developer tools (DevTools) that replaced tools like Firebug. Here's how to use them for DOM debugging:
Opening DevTools
- Chrome/Edge: F12 or Ctrl+Shift+I (Cmd+Opt+I on Mac)
- Firefox: F12 or Ctrl+Shift+I
- Right-click: "Inspect" on any element
Key DevTools Panels
- View and edit the DOM tree in real-time
- Inspect and modify CSS styles
- See computed styles (final applied values)
- Right-click elements to copy, delete, or edit
- Run JavaScript commands directly
$0- Reference to currently selected element$("selector")- Shorthand for querySelector$$("selector")- Shorthand for querySelectorAll
Debugging with Breakpoints
In the Sources panel, you can set breakpoints to pause code execution:
function updateElement() {
const el = document.getElementById("myElement");
debugger; // Code pauses here when DevTools is open
el.textContent = "Updated!";
}
Useful Console Commands
// Inspect selected element
console.dir($0); // Show all properties
// Find elements
$$("button") // All buttons on page
// Monitor events
monitorEvents($0, "click"); // Log all click events on element
// Copy to clipboard
copy($0.outerHTML); // Copy element's HTML
Quick Quizzes
Quiz 1: Which global object provides information about the current URL?
Quiz 2: What is the safest way to insert user-provided text into a DOM element?
Quiz 3: What does classList.toggle("active") do?
Quiz 4: Why should you use firstElementChild instead of firstChild?
Hands-On Exercises
DOM Manipulation
Practice creating and styling elements dynamically. Modify the code to create a styled card with:
- A title and description
- Padding and background color
- Rounded corners and a border
DOM Traversal
Practice navigating the DOM tree. Write code that:
- Creates a list with multiple items
- Traverses the list using firstElementChild and nextElementSibling
- Styles each item during traversal