Docs
Module-17-DOM-Manipulation
10.1 DOM Basics
Overview
The Document Object Model (DOM) is a programming interface that represents HTML and XML documents as a tree structure. Each element, attribute, and piece of text becomes a node in this tree, allowing JavaScript to dynamically access and manipulate the document's content, structure, and styles.
The DOM Tree Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DOM TREE STRUCTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β document β
β β β
β <html> β
β / \ β
β <head> <body> β
β β β β
β <title> <div> β
β β / \ β
β "Page" <h1> <p> β
β β β β
β "Hello" "World" β
β β
β Each box is a NODE: β
β - Element nodes: <html>, <body>, <div>, etc. β
β - Text nodes: "Page", "Hello", "World" β
β - Attribute nodes: id, class, href, etc. β
β - Comment nodes: <!-- comments --> β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Node Types
| Type | nodeType | Description | Example |
|---|---|---|---|
| Element | 1 | HTML tags | <div>, <p> |
| Text | 3 | Text content | "Hello World" |
| Comment | 8 | HTML comments | <!-- note --> |
| Document | 9 | The document | document |
| DocumentFragment | 11 | Lightweight container | createDocumentFragment() |
const element = document.body;
console.log(element.nodeType); // 1 (Element)
console.log(element.nodeName); // "BODY"
console.log(element.nodeValue); // null (elements have no value)
const text = element.firstChild;
console.log(text.nodeType); // 3 (Text)
console.log(text.nodeValue); // The text content
Selecting Elements
Single Element Selection
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SINGLE ELEMENT SELECTORS β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β getElementById('id') β
β βββ Returns: Single element or null β
β βββ Speed: Fastest β
β βββ Usage: document.getElementById('header') β
β β
β querySelector('selector') β
β βββ Returns: First matching element or null β
β βββ Speed: Moderate β
β βββ Usage: document.querySelector('.nav-item') β
β element.querySelector('span') β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// By ID - fastest method
const header = document.getElementById('header');
// By CSS selector - most flexible
const firstButton = document.querySelector('button');
const navLink = document.querySelector('.nav-link');
const emailInput = document.querySelector('input[type="email"]');
const firstChild = document.querySelector('ul > li:first-child');
Multiple Element Selection
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MULTIPLE ELEMENT SELECTORS β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β querySelectorAll('selector') β
β βββ Returns: Static NodeList β
β βββ Iterable: Yes (forEach, for...of) β
β βββ Live: No (doesn't update) β
β β
β getElementsByClassName('class') β
β βββ Returns: Live HTMLCollection β
β βββ Iterable: No (use Array.from) β
β βββ Live: Yes (updates automatically) β
β β
β getElementsByTagName('tag') β
β βββ Returns: Live HTMLCollection β
β βββ Iterable: No β
β βββ Live: Yes β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Static NodeList - use when you want a snapshot
const items = document.querySelectorAll('.menu-item');
items.forEach((item) => console.log(item.textContent));
// Live HTMLCollection - updates when DOM changes
const buttons = document.getElementsByClassName('btn');
console.log(buttons.length); // Changes as buttons are added/removed
// Convert to array for array methods
const buttonsArray = Array.from(buttons);
buttonsArray.filter((btn) => btn.classList.contains('primary'));
Static vs Live Collections
const container = document.getElementById('container');
// Static - querySelectorAll
const staticList = container.querySelectorAll('p');
console.log(staticList.length); // e.g., 3
// Live - getElementsByTagName
const liveList = container.getElementsByTagName('p');
console.log(liveList.length); // e.g., 3
// Add a new paragraph
const newP = document.createElement('p');
container.appendChild(newP);
console.log(staticList.length); // Still 3 (static)
console.log(liveList.length); // Now 4 (live)
DOM Traversal
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DOM TRAVERSAL β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ β
β β parentNode β β
β βparentElementβ β
β ββββββββ¬βββββββ β
β β β
β previousSibling βββββββββββΌββββββββββΊ nextSibling β
β previousElement β nextElement β
β Sibling β Sibling β
β ββββββββ΄βββββββ β
β β element β β
β ββββββββ¬βββββββ β
β β β
β βββββββββββββββ΄ββββββββββββββ β
β β β β
β firstChild lastChild β
β firstElementChild lastElementChild β
β β
β β β β β
β βΌ βΌ βΌ β
β child child child β
β β
β children (HTMLCollection of element children) β
β childNodes (NodeList of all child nodes) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Parent Navigation
const item = document.querySelector('.item');
// Parent element
const parent = item.parentElement; // <ul> or whatever contains it
const parentNode = item.parentNode; // Usually same, can be #document
// Go up multiple levels
const grandparent = item.parentElement.parentElement;
// Find closest ancestor matching selector
const container = item.closest('.container');
const form = item.closest('form'); // null if not in a form
Child Navigation
const list = document.querySelector('ul');
// Element children only (no text nodes)
const firstItem = list.firstElementChild;
const lastItem = list.lastElementChild;
const allItems = list.children; // HTMLCollection
// All nodes including text (whitespace)
const firstNode = list.firstChild; // Could be text node
const allNodes = list.childNodes; // NodeList
// Check if has children
const hasChildren = list.hasChildNodes();
const childCount = list.children.length;
Sibling Navigation
const middle = document.querySelector('.middle');
// Element siblings
const prev = middle.previousElementSibling;
const next = middle.nextElementSibling;
// All sibling nodes (including text)
const prevNode = middle.previousSibling;
const nextNode = middle.nextSibling;
// Get all siblings
function getSiblings(element) {
return Array.from(element.parentElement.children).filter(
(child) => child !== element
);
}
Common DOM Properties
Element Properties
| Property | Description | Example |
|---|---|---|
id | Element's ID | element.id = 'main' |
className | Class string | element.className = 'a b' |
classList | Class manipulation | element.classList.add('new') |
tagName | Tag name (uppercase) | element.tagName // "DIV" |
innerHTML | HTML content | element.innerHTML = '<b>Hi</b>' |
textContent | Text only | element.textContent = 'Hello' |
innerText | Visible text | element.innerText |
textContent vs innerHTML vs innerText
const div = document.createElement('div');
div.innerHTML = '<p>Hello <strong>World</strong></p>';
console.log(div.innerHTML); // '<p>Hello <strong>World</strong></p>'
console.log(div.textContent); // 'Hello World'
console.log(div.innerText); // 'Hello World' (respects CSS)
// Security: textContent is safer (no HTML parsing)
const userInput = '<script>alert("XSS")</script>';
div.textContent = userInput; // Safe - displays as text
div.innerHTML = userInput; // DANGER - could execute script
The classList API
const element = document.querySelector('.box');
// Add classes
element.classList.add('active');
element.classList.add('visible', 'highlight'); // Multiple
// Remove classes
element.classList.remove('hidden');
element.classList.remove('a', 'b', 'c'); // Multiple
// Toggle class
element.classList.toggle('active'); // Add or remove
element.classList.toggle('dark', isDarkMode); // Force add/remove
// Check for class
const isActive = element.classList.contains('active');
// Replace class
element.classList.replace('old-class', 'new-class');
// Iterate classes
element.classList.forEach((cls) => console.log(cls));
// Get class at index
const firstClass = element.classList.item(0);
Attributes
const link = document.querySelector('a');
// Get attribute
const href = link.getAttribute('href');
const target = link.getAttribute('target');
// Set attribute
link.setAttribute('href', 'https://example.com');
link.setAttribute('target', '_blank');
// Check if attribute exists
const hasTitle = link.hasAttribute('title');
// Remove attribute
link.removeAttribute('target');
// Data attributes
const card = document.querySelector('.card');
card.dataset.id = '123'; // Sets data-id="123"
const id = card.dataset.id; // Gets data-id value
card.dataset.userName = 'John'; // Sets data-user-name="John"
Document Properties and Methods
// Document references
document.documentElement; // <html>
document.head; // <head>
document.body; // <body>
document.title; // Page title
// Document information
document.URL; // Current URL
document.domain; // Domain name
document.referrer; // Previous page URL
// All forms, images, links
document.forms; // HTMLCollection of <form>
document.images; // HTMLCollection of <img>
document.links; // HTMLCollection of <a> with href
Performance Considerations
Selector Performance
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SELECTOR PERFORMANCE (Fastest to Slowest) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. getElementById('id') ββββββββββββββββββ Fastest β
β β
β 2. getElementsByClassName('cls') ββββββββββββββββ Fast β
β β
β 3. getElementsByTagName('tag') βββββββββββββββ Fast β
β β
β 4. querySelector('#id') ββββββββββββββ Good β
β β
β 5. querySelector('.class') ββββββββββββ Good β
β β
β 6. querySelectorAll('.items') ββββββββββ Medium β
β β
β 7. querySelector('complex > sel') ββββββββ Slower β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Best Practices
// β Avoid repeated queries
for (let i = 0; i < 100; i++) {
document.querySelector('.item').style.color = 'red';
}
// β
Cache the reference
const item = document.querySelector('.item');
for (let i = 0; i < 100; i++) {
item.style.color = 'red';
}
// β Avoid querying in loops
items.forEach(() => {
const container = document.getElementById('container');
// ...
});
// β
Query once outside loop
const container = document.getElementById('container');
items.forEach(() => {
// Use container
});
// β
Scope queries to parent elements
const form = document.getElementById('myForm');
const input = form.querySelector('input'); // Only searches within form
Key Takeaways
- β’DOM is a tree - HTML becomes a hierarchical node structure
- β’Use querySelector/querySelectorAll - Most flexible selection methods
- β’Cache DOM references - Avoid repeated queries
- β’getElementById is fastest - Use when selecting by ID
- β’Static vs Live - querySelectorAll is static, getElementsBy* is live
- β’Use textContent over innerHTML - Safer and faster for text
- β’classList for classes - Modern API for class manipulation
- β’Scope your queries - Search within parent elements when possible