What is the DOM?
The DOM (Document Object Model) is a programming interface that represents your HTML document as a tree of objects. It allows JavaScript to access and manipulate the content, structure, and styles of web pages.
Think of the DOM like:
- Family Tree: HTML elements act like family members connected in a tree structure.
- Blueprint: A structured representation of your webpage that JavaScript can read and modify.
- Bridge: Connects your HTML with JavaScript to enable dynamic behavior.
- Live Document: A live, interactive version of your HTML page that updates in real time.
Why is the DOM Important?
The DOM enables you to:
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Hello World</h1>
<p>Welcome to my page</p>
</body>
</html>
The DOM Tree Structure:
Selecting Elements
Before you can manipulate elements, you need to select them. JavaScript provides several methods to find elements in the DOM.
getElementById: Select by ID
The getElementById() method selects an element by its unique id attribute. Returns a single element or null if not found.
let title = document.getElementById('title');
console.log(title); // <h1 id="title">Welcome</h1>
let intro = document.getElementById('intro');
console.log(intro.textContent); // This is my website
let button = document.getElementById('myButton');
console.log(button); // <button id="myButton">Click Me</button>
<div id="container">
<h2 id="heading">My Heading</h2>
<p id="paragraph">Some text here</p>
</div>
<script>
let heading = document.getElementById('heading');
let paragraph = document.getElementById('paragraph');
console.log('Heading:', heading.textContent); // Heading: My Heading
console.log('Paragraph:', paragraph.textContent); // Paragraph: Some text here
</script>
querySelector: Select with CSS Selectors
The querySelector() method uses CSS selectors to find elements. Returns the first matching element or null.
let element = document.querySelector('cssSelector');
// Select by tag name
let heading = document.querySelector('h1');
// Select by class
let button = document.querySelector('.btn');
// Select by ID (use # symbol)
let title = document.querySelector('#title');
// Select by attribute
let input = document.querySelector('input[type="text"]');
// Select nested elements
let listItem = document.querySelector('ul li');
<div class="container">
<h1 class="title">Main Title</h1>
<p class="text">First paragraph</p>
<p class="text">Second paragraph</p>
<button class="btn primary">Submit</button>
</div>
<script>
// Select by class (gets first match)
let title = document.querySelector('.title');
console.log(title.textContent); // Main Title
// Select by tag name
let firstParagraph = document.querySelector('p');
console.log(firstParagraph.textContent); // First paragraph
// Select by multiple classes
let button = document.querySelector('.btn.primary');
console.log(button.textContent); // Submit
// Select nested element
let nestedP = document.querySelector('.container p');
console.log(nestedP.textContent); // First paragraph
</script>
querySelectorAll: Select Multiple Elements
The querySelectorAll() method returns a NodeList (array-like collection) of all matching elements.
<ul>
<li class="item">Item 1</li>
<li class="item">Item 2</li>
<li class="item">Item 3</li>
</ul>
<script>
// Select all list items
let items = document.querySelectorAll('.item');
console.log(items.length); // 3
// Loop through all items
items.forEach(item => {
console.log(item.textContent);
});
// Output:
// Item 1
// Item 2
// Item 3
</script>
Comparison: getElementById vs querySelector
<h1 id="title">Hello</h1>
<script>
// Both select the same element
let title1 = document.getElementById('title');
let title2 = document.querySelector('#title');
console.log(title1 === title2); // true (same element)
// getElementById is slightly faster
// querySelector is more flexible (uses CSS selectors)
</script>
When to use each:
- getElementById: Fast and simple; use when you have a unique ID.
- querySelector: Flexible; use when working with classes or complex CSS selectors.
- querySelectorAll: Ideal when you need to select multiple elements at once.
Reading and Modifying Element Content
Once you've selected an element, you can read or change its content using various properties.
textContent: Plain Text
<p id="message">Hello World</p>
<script>
let message = document.getElementById('message');
// Read content
console.log(message.textContent); // Hello World
// Modify content
message.textContent = 'Hello JavaScript!';
// Now displays: Hello JavaScript!
</script>
innerHTML: HTML Content
The innerHTML property gets or sets HTML content (including tags).
<div id="content">
<p>Original text</p>
</div>
<script>
let content = document.getElementById('content');
// Read HTML content
console.log(content.innerHTML); // <p>Original text</p>
// Set new HTML content
content.innerHTML = '<h2>New Title</h2><p>New paragraph</p>';
// Now displays formatted HTML
</script>
<!DOCTYPE html>
<html>
<body>
<h1 id="title">Welcome</h1>
<p id="intro">Click the button to change this text</p>
<button id="changeBtn">Change Content</button>
<script>
let title = document.getElementById('title');
let intro = document.getElementById('intro');
let button = document.getElementById('changeBtn');
button.addEventListener('click', function() {
title.textContent = 'Content Changed!';
intro.textContent = 'The content has been updated successfully.';
});
</script>
</body>
</html>
textContent vs innerHTML
<div id="demo"></div>
<script>
let demo = document.getElementById('demo');
// Using textContent (treats HTML as text)
demo.textContent = '<strong>Bold text</strong>';
// Displays: <strong>Bold text</strong> (as plain text)
// Using innerHTML (renders HTML)
demo.innerHTML = '<strong>Bold text</strong>';
// Displays: Bold text (actually bold)
</script>
Security Note: Be careful with innerHTML when using user input - it can expose you to XSS attacks. Use textContent when you don't need HTML formatting.
value: Form Input Values
<input type="text" id="username" placeholder="Enter name">
<button id="submitBtn">Submit</button>
<p id="greeting"></p>
<script>
let input = document.getElementById('username');
let button = document.getElementById('submitBtn');
let greeting = document.getElementById('greeting');
button.addEventListener('click', function() {
let name = input.value; // Get input value
greeting.textContent = 'Hello, ' + name + '!';
});
</script>
Changing Styles with JavaScript
JavaScript can modify CSS styles dynamically using the style property.
Inline Style Syntax
Access styles using camelCase (CSS background-color becomes backgroundColor): element.style.propertyName = 'value';
<h1 id="title">Hello World</h1>
<button id="changeColor">Change Color</button>
<script>
let title = document.getElementById('title');
let button = document.getElementById('changeColor');
button.addEventListener('click', function() {
title.style.color = 'red';
});
</script>
<div id="box" style="width: 100px; height: 100px; background: blue;"></div>
<button id="styleBtn">Change Styles</button>
<script>
let box = document.getElementById('box');
let button = document.getElementById('styleBtn');
button.addEventListener('click', function() {
box.style.width = '200px';
box.style.height = '200px';
box.style.backgroundColor = 'green';
box.style.borderRadius = '10px';
box.style.border = '3px solid black';
});
</script>
Working with CSS Classes
Instead of inline styles, you can add/remove CSS classes:
<!DOCTYPE html>
<html>
<head>
<style>
.highlight {
background-color: yellow;
font-weight: bold;
padding: 10px;
}
.large {
font-size: 24px;
}
</style>
</head>
<body>
<p id="text">This is some text</p>
<button id="highlightBtn">Highlight</button>
<button id="enlargeBtn">Enlarge</button>
<script>
let text = document.getElementById('text');
let highlightBtn = document.getElementById('highlightBtn');
let enlargeBtn = document.getElementById('enlargeBtn');
highlightBtn.addEventListener('click', function() {
text.classList.toggle('highlight');
});
enlargeBtn.addEventListener('click', function() {
text.classList.toggle('large');
});
</script>
</body>
</html>
let element = document.querySelector('.box');
// Add a class
element.classList.add('active');
// Remove a class
element.classList.remove('active');
// Toggle a class (add if absent, remove if present)
element.classList.toggle('active');
// Check if class exists
if (element.classList.contains('active')) {
console.log('Element has active class');
}
// Replace a class
element.classList.replace('old-class', 'new-class');
Practical DOM Manipulation Examples
Example 1: Todo List Application
<!DOCTYPE html>
<html>
<head>
<style>
.completed {
text-decoration: line-through;
color: gray;
}
#todoList {
list-style: none;
padding: 0;
}
#todoList li {
padding: 10px;
margin: 5px 0;
background: #f0f0f0;
cursor: pointer;
}
</style>
</head>
<body>
<h2>My Todo List</h2>
<input type="text" id="todoInput" placeholder="Enter a task">
<button id="addBtn">Add Task</button>
<ul id="todoList"></ul>
<script>
let input = document.getElementById('todoInput');
let addBtn = document.getElementById('addBtn');
let list = document.getElementById('todoList');
addBtn.addEventListener('click', function() {
let taskText = input.value;
if (taskText.trim() !== '') {
// Create new list item
let li = document.createElement('li');
li.textContent = taskText;
// Toggle completed on click
li.addEventListener('click', function() {
li.classList.toggle('completed');
});
// Add to list
list.appendChild(li);
// Clear input
input.value = '';
}
});
// Allow Enter key to add task
input.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
addBtn.click();
}
});
</script>
</body>
<!DOCTYPE html>
<html>
<head>
<style>
body {
transition: all 0.3s;
padding: 20px;
}
body.light-mode {
background-color: white;
color: black;
}
body.dark-mode {
background-color: #222;
color: white;
}
#toggleBtn {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 5px;
}
.light-mode #toggleBtn {
background-color: #333;
color: white;
}
.dark-mode #toggleBtn {
background-color: #fff;
color: #333;
}
</style>
</head>
<body class="light-mode">
<h1>Dark Mode Toggle</h1>
<p>Click the button to toggle between light and dark mode.</p>
<button id="toggleBtn">🌙 Dark Mode</button>
<script>
let body = document.body;
let toggleBtn = document.getElementById('toggleBtn');
toggleBtn.addEventListener('click', function() {
if (body.classList.contains('light-mode')) {
body.classList.remove('light-mode');
body.classList.add('dark-mode');
toggleBtn.textContent = '☀️ Light Mode';
} else {
body.classList.remove('dark-mode');
body.classList.add('light-mode');
toggleBtn.textContent = '🌙 Dark Mode';
}
});
</script>
</body>
</html>
Common DOM Mistakes
<script>
// ❌ WRONG - Script runs before HTML loads
let title = document.getElementById('title');
console.log(title); // null
</script>
<h1 id="title">Hello</h1>
<!-- ✅ CORRECT - Script after HTML -->
<h1 id="title">Hello</h1>
<script>
let title = document.getElementById('title');
console.log(title); // <h1> element
</script>
<!-- ✅ OR use DOMContentLoaded event -->
<script>
document.addEventListener('DOMContentLoaded', function() {
let title = document.getElementById('title');
console.log(title);
});
</script>
// ❌ WRONG - Missing quotes
let element = document.querySelector(#title);
// ✅ CORRECT - CSS selector in quotes
let element = document.querySelector('#title');
// ❌ RISKY - XSS vulnerability
let userInput = '<script>alert("Hacked!")</script>';
element.innerHTML = userInput; // Dangerous!
// ✅ SAFER - Use textContent
element.textContent = userInput; // Displays as plain text
DOM Best Practices
- Place scripts at the bottom of the body – Ensures HTML loads first
- Use
DOMContentLoaded– Wait for the DOM to be fully ready - Cache selectors – Store elements in variables instead of selecting repeatedly
- Use
textContentoverinnerHTML– When HTML formatting is not required - Check if an element exists – Before attempting to manipulate it
- Use
classListover inlinestyle– Improves maintainability - Use meaningful IDs and classes – Makes element selection clearer
- Separate concerns – Keep CSS in stylesheets and JavaScript in script files