JS HTML DOM & Element Selection
Bridge the gap between JavaScript code and the rendered browser document. Master the Document Object Model (DOM) tree hierarchy, query selectors (querySelector, querySelectorAll), content manipulation (textContent vs innerHTML), attribute bindings, classList, and high-performance element creation.
The DOM Tree Hierarchy & Selection Path
The Document Object Model converts flat HTML text into an in-memory tree of live object nodes. JavaScript traverses, modifies, or queries this tree in real time.
1. Element Selection: Modern vs. Legacy Methods
In modern production JavaScript, querySelector and querySelectorAll are the industry standard, replacing legacy method fragmentation:
| Modern Method | Legacy Counterpart | Returns | Why Modern is Superior |
|---|---|---|---|
document.querySelector(selector) |
document.getElementById(id) |
First matching Element or null. |
Accepts any valid CSS selector (classes, IDs, attributes, child combinators like .card > button.primary). |
document.querySelectorAll(selector) |
document.getElementsByClassName(cls) |
Static NodeList. |
Supports array-like methods (.forEach()) and is NOT a live mutating collection, avoiding mutation-during-iteration bugs! |
Precision CSS Selector Queries
// 1. Select by ID:
const submitBtn = document.querySelector('#submit-btn');
// 2. Select by Class and Attribute:
const activeTab = document.querySelector('.tab[data-selected="true"]');
// 3. Select all list items inside navigation:
const navLinks = document.querySelectorAll('nav.main-menu > ul > li > a');
// NodeList has native forEach:
navLinks.forEach(link => {
console.log('Target URL:', link.getAttribute('href'));
});
Try it in Playground
2. Content, Attributes & classList Manipulation
textContent (Safe)
Reads or writes pure text. Completely ignores HTML tags and encodes special characters, preventing XSS injection attacks.
innerHTML (Dangerous)
Parses text as HTML. Never use with unsanitized user inputs due to severe Cross-Site Scripting (XSS) vulnerabilities.
element.classList
Provides high-level class manipulation methods: .add(), .remove(), .toggle(), and .contains().
Manipulating Attributes and Classes
const card = document.querySelector('.product-card');
// Safe text insertion:
card.querySelector('.title').textContent = 'Mechanical Keyboard';
// Attribute manipulation:
card.setAttribute('data-in-stock', 'true');
console.log('Stock state:', card.dataset.inStock); // dataset maps data-in-stock
// classList API:
card.classList.add('highlight', 'shadow-lg');
card.classList.remove('dimmed');
card.classList.toggle('active'); // Toggles boolean presence!
console.log('Is active?', card.classList.contains('active')); // true
Try it in Playground
3. High-Performance Element Creation & DocumentFragment
Appending elements directly to the live DOM in a loop forces the browser to recalculate layout and repaint on every iteration (layout thrashing). Use DocumentFragment for batch inserts:
Batch Inserting with DocumentFragment
const users = ['Alice', 'Bob', 'Charlie', 'Diana'];
const userList = document.querySelector('#user-list');
// 1. Create a lightweight off-DOM fragment container:
const fragment = document.createDocumentFragment();
users.forEach(name => {
const li = document.createElement('li');
li.className = 'list-item text-light py-1';
li.textContent = name;
fragment.appendChild(li); // Appending to fragment does NOT trigger DOM reflow!
});
// 2. Single reflow insertion into the live DOM:
userList.appendChild(fragment);
Try it in Playground
Interactive Mini-Lab: Live Query Selector Tester
Test different CSS selector strings against the preview DOM container below to see matching nodes highlight in real time:
#item-1[data-role="user"]
.badge-vip
[data-role="admin"]
.badge-vip
Hands-on Challenge: Dynamic Notification Toast Dispatcher
Coding Challenge
Write a showToast(message, type = 'info', duration = 3000) utility that dynamically creates and injects animated toast alerts into the document body, complete with a manual close button and automatic removal:
- Create or reuse a fixed toast container (
#toast-container) on the body. - Build the toast element using
document.createElement()and sanitize content withtextContent. - Add appropriate styling classes based on
type('success', 'error', 'info'). - Remove the toast after
durationms (or when the close button is clicked).
/**
* Dynamic accessible toast notification dispatcher.
*/
function showToast(message, type = 'info', duration = 3000) {
// 1. Locate or create toast container:
let container = document.querySelector('#toast-container');
if (!container) {
container = document.createElement('div');
container.id = 'toast-container';
container.style.cssText = 'position: fixed; bottom: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; gap: 10px;';
document.body.appendChild(container);
}
// 2. Build toast card:
const toast = document.createElement('div');
toast.className = `toast-item p-3 rounded-3 text-light shadow-lg d-flex align-items-center justify-content-between`;
toast.style.minWidth = '280px';
toast.style.background = type === 'success' ? '#059669' : type === 'error' ? '#dc2626' : '#0284c7';
// Safe text span:
const textSpan = document.createElement('span');
textSpan.textContent = message; // Prevents XSS!
// Close button:
const closeBtn = document.createElement('button');
closeBtn.innerHTML = '×';
closeBtn.style.cssText = 'background: none; border: none; color: white; font-size: 18px; cursor: pointer; padding: 0 4px;';
const removeToast = () => {
toast.style.opacity = '0';
toast.style.transition = 'opacity 0.2s ease';
setTimeout(() => toast.remove(), 200);
};
closeBtn.onclick = removeToast;
toast.append(textSpan, closeBtn);
container.appendChild(toast);
// Auto-dismiss:
setTimeout(removeToast, duration);
}
// Verification:
showToast('Payment confirmed successfully!', 'success');
Chapter 27 Knowledge Check
Validate your mastery of DOM element selection, classList, and node insertion.
element.textContent strongly preferred over element.innerHTML when rendering user-submitted text?textContent automatically translates text into foreign languages.
textContent treats all input strictly as plain text, eliminating Cross-Site Scripting (XSS) HTML injection vulnerabilities.
innerHTML runs only in Internet Explorer.
textContent cannot be modified by JavaScript.
document.querySelector('.btn') return if THREE buttons matching class .btn exist on the page?Element in the document.
NodeList of three elements.
DocumentFragment when adding 100 new list items to the DOM?classList method will add a class if absent, and remove it if already present?classList.switch()
classList.toggle()
classList.replace()
classList.swap()
data-order-id="8492", how is it accessed in JavaScript via the dataset property?element.dataset['data-order-id']
element.dataset.orderId (converted to camelCase)
element.dataset.order_id
element.data.orderId