Docs
17.2-Modifying-the-DOM
10.2 Modifying the DOM
š Learning Objectives
By the end of this section, you will:
- ā¢Modify element content using innerHTML, textContent, and innerText
- ā¢Work with element attributes (get, set, remove)
- ā¢Manipulate CSS classes and inline styles
- ā¢Understand the differences between content properties
- ā¢Work with data attributes
š Table of Contents
- ā¢Modifying Content
- ā¢Working with Attributes
- ā¢CSS Class Manipulation
- ā¢Inline Styles
- ā¢Data Attributes
- ā¢Comparison Tables
Modifying Content
Content Properties Overview
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā <div id="box"> ā
ā Hello <strong>World</strong> ā
ā </div> ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā innerHTML: "Hello <strong>World</strong>" ā
ā ā³ Returns/sets HTML markup ā
ā ā
ā textContent: "Hello World" ā
ā ā³ Returns/sets all text (including hidden) ā
ā ā
ā innerText: "Hello World" ā
ā ā³ Returns/sets visible text only ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
innerHTML
const element = document.getElementById('container');
// Get HTML content
console.log(element.innerHTML);
// Set HTML content (parses HTML tags)
element.innerHTML = '<p>New <em>paragraph</em></p>';
// Append HTML content
element.innerHTML += '<span>More content</span>';
// Clear content
element.innerHTML = '';
ā ļø Security Warning: Never use innerHTML with user input!
// DANGEROUS - XSS vulnerability
element.innerHTML = userInput; // ā Never do this!
// SAFE - use textContent for user input
element.textContent = userInput; // ā Safe
textContent
const element = document.getElementById('title');
// Get text content (including hidden text)
console.log(element.textContent);
// Set text content (escapes HTML, no parsing)
element.textContent = '<p>This shows as plain text</p>';
// Result: literally displays "<p>This shows as plain text</p>"
innerText
const element = document.getElementById('content');
// Get visible text only (respects CSS)
console.log(element.innerText);
// Set visible text
element.innerText = 'New visible text';
Difference Visual
HTML:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā <div id="example"> ā
ā Visible text ā
ā <span style="display: none">Hidden text</span> ā
ā <script>// script content</script> ā
ā </div> ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Properties Return:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā innerHTML: "Visible text<span style=..." ā
ā (Full HTML including tags) ā
ā ā
ā textContent: "Visible text Hidden text ā
ā // script content" ā
ā (ALL text, including hidden) ā
ā ā
ā innerText: "Visible text" ā
ā (Only rendered/visible text) ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Working with Attributes
Attribute Methods
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Attribute Methods ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā element.getAttribute("name") ā Get attribute value ā
ā element.setAttribute("name", val) ā Set attribute value ā
ā element.removeAttribute("name") ā Remove attribute ā
ā element.hasAttribute("name") ā Check if exists (boolean) ā
ā ā
ā element.attributes ā All attributes (NamedNodeMap)
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Getting Attributes
const link = document.getElementById('myLink');
// Get attribute value
const href = link.getAttribute('href');
const target = link.getAttribute('target');
// Check if attribute exists
if (link.hasAttribute('disabled')) {
console.log('Link is disabled');
}
// Get all attributes
const attrs = link.attributes;
for (const attr of attrs) {
console.log(`${attr.name}: ${attr.value}`);
}
Setting Attributes
const img = document.getElementById('myImage');
// Set single attribute
img.setAttribute('src', 'new-image.jpg');
img.setAttribute('alt', 'Description of image');
// Set multiple attributes
const attributes = {
src: 'photo.jpg',
alt: 'A beautiful photo',
width: '300',
height: '200',
};
Object.entries(attributes).forEach(([name, value]) => {
img.setAttribute(name, value);
});
Removing Attributes
const button = document.getElementById('submitBtn');
// Remove single attribute
button.removeAttribute('disabled');
button.removeAttribute('aria-hidden');
// Toggle attribute presence
function toggleDisabled(element) {
if (element.hasAttribute('disabled')) {
element.removeAttribute('disabled');
} else {
element.setAttribute('disabled', '');
}
}
Direct Property Access vs getAttribute
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Property Access vs getAttribute ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā <a href="/page" id="link">Click</a> ā
ā ā
ā link.href ā
ā ā "https://example.com/page" (Full resolved URL) ā
ā ā
ā link.getAttribute("href") ā
ā ā "/page" (Exact attribute value) ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā Use PROPERTY for: Use getAttribute for: ā
ā ⢠Boolean values ⢠Custom attributes ā
ā ⢠Computed values ⢠Exact HTML value ā
ā ⢠Standard properties ⢠data-* attributes (or dataset) ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
CSS Class Manipulation
classList API
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā classList Methods ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā element.classList.add("class1", "class2") ā
ā ā³ Add one or more classes ā
ā ā
ā element.classList.remove("class1", "class2") ā
ā ā³ Remove one or more classes ā
ā ā
ā element.classList.toggle("class") ā
ā ā³ Add if missing, remove if present ā
ā ā
ā element.classList.toggle("class", condition) ā
ā ā³ Force add (true) or remove (false) ā
ā ā
ā element.classList.contains("class") ā
ā ā³ Check if class exists (returns boolean) ā
ā ā
ā element.classList.replace("old", "new") ā
ā ā³ Replace one class with another ā
ā ā
ā element.className ā
ā ā³ Get/set entire class string ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Basic Class Operations
const box = document.getElementById('box');
// Add classes
box.classList.add('active');
box.classList.add('highlight', 'animated', 'fade-in');
// Remove classes
box.classList.remove('hidden');
box.classList.remove('old-class', 'deprecated');
// Toggle class
box.classList.toggle('visible');
// Toggle with condition
const isLoggedIn = true;
box.classList.toggle('authenticated', isLoggedIn);
// Check for class
if (box.classList.contains('active')) {
console.log('Box is active');
}
// Replace class
box.classList.replace('old-theme', 'new-theme');
className Property
const element = document.getElementById('myElement');
// Get all classes as string
console.log(element.className); // "class1 class2 class3"
// Set all classes (replaces existing)
element.className = 'new-class another-class';
// Append to existing (avoid - use classList.add instead)
element.className += ' additional-class';
Practical Examples
// Toggle dark mode
function toggleDarkMode() {
document.body.classList.toggle('dark-mode');
}
// Tab switching
function activateTab(tabId) {
// Remove active from all tabs
document.querySelectorAll('.tab').forEach((tab) => {
tab.classList.remove('active');
});
// Add active to clicked tab
document.getElementById(tabId).classList.add('active');
}
// Conditional styling
function updateStatus(element, status) {
element.classList.remove('success', 'error', 'pending');
element.classList.add(status);
}
Inline Styles
style Property
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Inline Style Methods ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā element.style.property = value ā
ā ā³ Set individual CSS property ā
ā ā
ā element.style.cssText = "..." ā
ā ā³ Set multiple styles as string ā
ā ā
ā element.style.setProperty(name, value) ā
ā ā³ Set property (supports CSS variables) ā
ā ā
ā element.style.removeProperty(name) ā
ā ā³ Remove inline style ā
ā ā
ā getComputedStyle(element) ā
ā ā³ Get final computed styles ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Setting Inline Styles
const box = document.getElementById('box');
// Set individual properties (camelCase)
box.style.backgroundColor = 'blue';
box.style.fontSize = '16px';
box.style.marginTop = '20px';
box.style.borderRadius = '5px';
// CSS property names with hyphens ā camelCase
// background-color ā backgroundColor
// font-size ā fontSize
// z-index ā zIndex
// Set using setProperty (use CSS names)
box.style.setProperty('background-color', 'blue');
box.style.setProperty('--custom-color', 'red'); // CSS variables
Multiple Styles
const element = document.getElementById('myElement');
// Using cssText (replaces all inline styles)
element.style.cssText = `
color: white;
background-color: black;
padding: 10px;
border-radius: 5px;
`;
// Using Object.assign
Object.assign(element.style, {
color: 'white',
backgroundColor: 'black',
padding: '10px',
borderRadius: '5px',
});
// Using a style object helper
function applyStyles(element, styles) {
Object.entries(styles).forEach(([prop, value]) => {
element.style[prop] = value;
});
}
applyStyles(element, {
width: '200px',
height: '100px',
display: 'flex',
});
Getting Computed Styles
const element = document.getElementById('myElement');
// Get computed style (final rendered style)
const computedStyle = getComputedStyle(element);
console.log(computedStyle.width); // "200px"
console.log(computedStyle.backgroundColor); // "rgb(0, 0, 0)"
console.log(computedStyle.fontSize); // "16px"
// Get pseudo-element styles
const beforeStyle = getComputedStyle(element, '::before');
console.log(beforeStyle.content);
Removing Styles
const element = document.getElementById('myElement');
// Remove single property
element.style.backgroundColor = '';
// OR
element.style.removeProperty('background-color');
// Remove all inline styles
element.style.cssText = '';
// OR
element.removeAttribute('style');
Data Attributes
data-* Attributes
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Data Attributes ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā HTML: ā
ā <div id="user" ā
ā data-user-id="123" ā
ā data-user-name="John" ā
ā data-is-active="true"> ā
ā </div> ā
ā ā
ā JavaScript Access: ā
ā ā
ā element.dataset.userId ā "123" ā
ā element.dataset.userName ā "John" ā
ā element.dataset.isActive ā "true" ā
ā ā
ā Naming Convention: ā
ā data-user-id ā dataset.userId (kebab-case ā camelCase) ā
ā data-user-name ā dataset.userName ā
ā data-is-active ā dataset.isActive ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Reading Data Attributes
// HTML: <div id="product" data-product-id="456" data-price="29.99">
const product = document.getElementById('product');
// Using dataset (recommended)
console.log(product.dataset.productId); // "456"
console.log(product.dataset.price); // "29.99"
// Using getAttribute
console.log(product.getAttribute('data-product-id')); // "456"
// Get all data attributes
console.log(product.dataset);
// DOMStringMap { productId: "456", price: "29.99" }
Setting Data Attributes
const element = document.getElementById('item');
// Using dataset (recommended)
element.dataset.itemId = '789';
element.dataset.category = 'electronics';
element.dataset.inStock = 'true';
// Using setAttribute
element.setAttribute('data-item-id', '789');
// Dynamic data attribute
const key = 'color';
element.dataset[key] = 'blue';
Removing Data Attributes
const element = document.getElementById('item');
// Using delete
delete element.dataset.itemId;
// Using removeAttribute
element.removeAttribute('data-item-id');
Practical Use Cases
// Store component state
const modal = document.getElementById('modal');
modal.dataset.state = 'closed';
function toggleModal() {
if (modal.dataset.state === 'closed') {
modal.classList.add('open');
modal.dataset.state = 'open';
} else {
modal.classList.remove('open');
modal.dataset.state = 'closed';
}
}
// Store configuration
const slider = document.getElementById('slider');
// <div id="slider" data-auto-play="true" data-delay="3000">
const autoPlay = slider.dataset.autoPlay === 'true';
const delay = parseInt(slider.dataset.delay, 10);
// Store relationships
// <button data-target="#modal1">Open Modal</button>
document.querySelectorAll('[data-target]').forEach((btn) => {
btn.addEventListener('click', () => {
const targetId = btn.dataset.target;
document.querySelector(targetId).classList.toggle('visible');
});
});
Comparison Tables
Content Properties Comparison
| Property | Returns | Parses HTML | Performance | Hidden Text | Script Content |
|---|---|---|---|---|---|
innerHTML | HTML string | Yes | Slower | Includes | Includes |
textContent | Plain text | No | Faster | Includes | Includes |
innerText | Visible text | No | Slowest* | Excludes | Excludes |
*innerText triggers reflow to determine visibility
When to Use Each
| Use Case | Recommended Property |
|---|---|
| Insert HTML content | innerHTML (with sanitization) |
| Display user input | textContent (XSS safe) |
| Get visible text | innerText |
| Clear element | innerHTML = "" or textContent = "" |
| Copy text content | textContent |
Attribute Access Comparison
| Method | Use Case | Example |
|---|---|---|
| Property access | Standard HTML attributes | element.id, element.href |
getAttribute() | Custom attributes, exact value | element.getAttribute("data-id") |
dataset | data-* attributes | element.dataset.id |
Class Manipulation Comparison
| Method | Old Way | Modern Way |
|---|---|---|
| Add class | el.className += " new" | el.classList.add("new") |
| Remove class | Complex string manipulation | el.classList.remove("old") |
| Toggle class | Check + add/remove | el.classList.toggle("active") |
| Check class | el.className.indexOf("...") | el.classList.contains("...") |
š” Key Takeaways
- ā¢Content Modification: Use
textContentfor safety,innerHTMLwhen you need HTML parsing - ā¢Attributes: Use
datasetfor data-* attributes, direct properties for standard attributes - ā¢Classes: Always use
classListfor class manipulation - it's cleaner and safer - ā¢Styles: Prefer CSS classes over inline styles; use
getComputedStyleto read computed values - ā¢Security: Never use
innerHTMLwith unsanitized user input
š Next Steps
Continue to 10.3 Creating and Removing Elements to learn how to dynamically create, insert, and remove DOM elements.