Part 1 - Understanding the Document Object Model (DOM)
The Document Object Model (DOM) is a programming interface for web documents. When your browser loads an HTML file, it parses the tags and constructs a live, tree-like structure of JavaScript objects representing every element, attribute, and text snippet on the page.
Through JavaScript, you can read and manipulate this tree dynamically — changing text, modifying styling, listening to user gestures, adding animations, and swapping content without reloading the page.
// The global window and document objects
console.log(window.document.title);
console.log(document.body);
Part 2 - Modern Element Selection
In modern JavaScript, standard CSS selector queries have superseded older, clunky methods:
// 1. Select the first matching element
const mainHeading = document.querySelector('h1');
const activeCard = document.querySelector('.card.active');
const submitBtn = document.querySelector('#btn-submit');
// 2. Select ALL matching elements (returns a static NodeList)
const allButtons = document.querySelectorAll('.btn');
// Iterating through a NodeList
allButtons.forEach(btn => {
btn.style.cursor = 'pointer';
});
// Convert NodeList to genuine Array for map/filter
const buttonArray = Array.from(allButtons);
Part 3 - Modifying Elements, Content & Classes
1. Text vs. HTML Content
Always choose textContent over innerHTML when inserting user-supplied data to prevent security holes (Cross-Site Scripting / XSS).
const banner = document.querySelector('.banner');
// Safe plain text insertion
banner.textContent = "Welcome back, Somil!";
// HTML parsing (use only with trusted developer-defined markup)
banner.innerHTML = "<span class='badge'>PRO</span> Welcome back!";
2. classList: The Cleanest Way to Style
Rather than modifying inline element.style directly, toggle CSS classes:
const modal = document.querySelector('.modal');
modal.classList.add('visible'); // Adds class
modal.classList.remove('hidden'); // Removes class
modal.classList.toggle('active'); // Toggles on/off
modal.classList.contains('active'); // Returns true/false
3. Working with Attributes & Data-Attributes
const profileImg = document.querySelector('#avatar');
profileImg.setAttribute('src', 'user.webp');
profileImg.setAttribute('alt', 'User profile portrait');
// Accessing custom HTML5 data-* attributes
// HTML: <div class="card" data-user-id="42" data-role="admin">
const card = document.querySelector('.card');
console.log(card.dataset.userId); // "42"
console.log(card.dataset.role); // "admin"
Part 4 - Creating, Appending & Deleting DOM Elements
// 1. Create element in memory
const newCard = document.createElement('article');
newCard.classList.add('card');
// 2. Populate contents
const title = document.createElement('h3');
title.textContent = 'Mastering Modern Web Architecture';
newCard.appendChild(title);
// 3. Mount onto active document
const container = document.querySelector('.card-container');
container.append(newCard); // .append() can take multiple nodes or strings!
// 4. Removing an element
newCard.remove(); // Removes itself cleanly from the DOM
Part 5 - Event Listeners & The Event Object
Interactive websites react to user inputs: clicks, key presses, mouse moves, scrolls, and form submits.
const button = document.querySelector('#theme-toggle');
button.addEventListener('click', (event) => {
console.log('Button was clicked!');
console.log('Event target:', event.target);
console.log('Mouse coordinates:', event.clientX, event.clientY);
});
// Preventing default browser behavior (e.g. form refresh)
const loginForm = document.querySelector('#login-form');
loginForm.addEventListener('submit', (e) => {
e.preventDefault(); // Stops page from reloading!
console.log('Form submission intercepted for async validation');
});
Part 6 - Event Bubbling & Event Delegation
When an event fires on an element, it doesn't just trigger there. It travels upward through its ancestors all the way to window in a phase called bubbling.
Event Delegation is an optimization pattern where you place a single event listener on a common parent container instead of attaching hundreds of separate listeners to individual children.
// Parent list element
const todoList = document.querySelector('#todo-list');
todoList.addEventListener('click', (event) => {
// Check if the clicked target was a delete button
if (event.target.matches('.btn-delete')) {
const item = event.target.closest('li');
item.remove();
console.log('Item deleted via delegation!');
}
});
Part 7 - Interactive Mini-Project: Dynamic Todo Manager
Here is a complete, real-world snippet demonstrating DOM creation, event delegation, and class toggling:
const taskInput = document.querySelector('#task-input');
const addBtn = document.querySelector('#add-btn');
const list = document.querySelector('#task-list');
function addTask() {
const text = taskInput.value.trim();
if (!text) return;
const li = document.createElement('li');
li.innerHTML = `
<span class="task-text">${text}</span>
<button class="btn-done">✓</button>
<button class="btn-del">✕</button>
`;
list.appendChild(li);
taskInput.value = '';
}
addBtn.addEventListener('click', addTask);
// Event delegation on parent list
list.addEventListener('click', (e) => {
if (e.target.matches('.btn-del')) {
e.target.closest('li').remove();
} else if (e.target.matches('.btn-done')) {
e.target.closest('li').classList.toggle('completed');
}
});