Introduction to DOM Manipulation
Creating New Elements
The createElement() Method
The document.createElement() method is the primary way to create new HTML elements dynamically in JavaScript. This method creates an element node in memory, which you can then customize before adding it to the page.
const element = document.createElement(tagName);
// Create a div element
const newDiv = document.createElement('div');
// Create a paragraph
const paragraph = document.createElement('p');
// Create a button
const button = document.createElement('button');
// Create an image
const image = document.createElement('img');
// Create a list item
const listItem = document.createElement('li');
Adding Content to New Elements
Once you've created an element, you'll typically want to add content to it. There are several ways to do this:
Using textContent:
const heading = document.createElement('h2');
heading.textContent = 'Welcome to My Website';
Using innerHTML (for HTML content):
const div = document.createElement('div');
div.innerHTML = '<strong>Bold text</strong> and normal text';
const paragraph = document.createElement('p');
const textNode = document.createTextNode('This is a text node');
paragraph.appendChild(textNode);
Best Practice: Use textContent for plain text (safer and faster) and innerHTML only when you need to include HTML markup.
Adding and Removing Elements
Adding Elements to the DOM
After creating an element, you need to insert it into the document to make it visible. JavaScript provides several methods for this purpose.
appendChild()
const container = document.getElementById('container');
const newParagraph = document.createElement('p');
newParagraph.textContent = 'This is a new paragraph';
container.appendChild(newParagraph);
append()
const div = document.getElementById('myDiv');
// Can append multiple elements at once
div.append('Some text', document.createElement('br'), 'More text');
// Can append multiple elements
const p1 = document.createElement('p');
const p2 = document.createElement('p');
div.append(p1, p2);
insertBefore()
Insert a new element before an existing element
const parent = document.getElementById('parent');
const newElement = document.createElement('div');
const referenceElement = document.getElementById('reference');
parent.insertBefore(newElement, referenceElement);
insertAdjacentElement()
This method provides precise control over where to insert an element.
const targetElement = document.getElementById('target');
const newElement = document.createElement('div');
// Positions: 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
targetElement.insertAdjacentElement('beforebegin', newElement);
- beforebegin: Inserts content before the element itself
- afterbegin: Inserts content inside the element, before its first child
- beforeend: Inserts content inside the element, after its last child
- afterend: Inserts content after the element itself
Removing Elements from the DOM
remove()
The modern and simplest way to remove an element.
const element = document.getElementById('myElement');
element.remove();
removeChild()
The traditional method that requires access to the parent element.
const parent = document.getElementById('parent');
const child = document.getElementById('child');
parent.removeChild(child);
Replacing Elements
const parent = document.getElementById('parent');
const oldElement = document.getElementById('old');
const newElement = document.createElement('div');
parent.replaceChild(newElement, oldElement);
// Or using the newer replaceWith() method
oldElement.replaceWith(newElement);
Modifying Attributes
Attributes provide additional information about HTML elements. JavaScript offers multiple ways to read, set, and remove attributes dynamically.
getAttribute() and setAttribute()
These methods work with any HTML attribute.
const link = document.getElementById('myLink');
// Get an attribute value
const href = link.getAttribute('href');
console.log(href); // Output: the URL
// Set an attribute
link.setAttribute('href', 'https://example.com');
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener noreferrer');
Direct Property Access
const image = document.getElementById('myImage');
// Setting attributes via properties
image.src = 'photo.jpg';
image.alt = 'A beautiful landscape';
image.width = 300;
image.height = 200;
const input = document.getElementById('username');
input.value = 'JohnDoe';
input.placeholder = 'Enter your username';
input.disabled = false;
hasAttribute() and removeAttribute()
Check for the existence of attributes and remove them when needed.
const button = document.getElementById('submitBtn');
// Check if attribute exists
if (button.hasAttribute('disabled')) {
console.log('Button is disabled');
}
// Remove an attribute
button.removeAttribute('disabled');
// Check for data attributes
if (button.hasAttribute('data-user-id')) {
const userId = button.getAttribute('data-user-id');
}
Working with Data Attributes
Data attributes (data-*) provide a way to store custom data in HTML elements
const element = document.getElementById('product');
// Setting data attributes
element.setAttribute('data-product-id', '12345');
element.setAttribute('data-price', '29.99');
element.setAttribute('data-category', 'electronics');
// Reading data attributes (two methods)
const productId = element.getAttribute('data-product-id');
// or using the dataset property
const price = element.dataset.price;
const category = element.dataset.category;
// Setting via dataset
element.dataset.inStock = 'true';
ClassList Manipulation
The classList property provides a powerful and convenient way to manage CSS classes on elements. It's more efficient and cleaner than manipulating the className property directly.
classList.add()
Add one or more classes to an element.
const element = document.getElementById('myElement');
// Add a single class
element.classList.add('active');
// Add multiple classes
element.classList.add('highlight', 'animated', 'fade-in');
classList.remove()
const element = document.getElementById('myElement');
// Remove a single class
element.classList.remove('active');
// Remove multiple classes
element.classList.remove('highlight', 'animated');
classList.toggle()
Toggle a class on or off. This is extremely useful for interactive elements.
const button = document.getElementById('menuButton');
const menu = document.getElementById('menu');
button.addEventListener('click', () => {
// Toggles the 'open' class
menu.classList.toggle('open');
});
// Toggle with a condition (second parameter)
const isVisible = true;
menu.classList.toggle('hidden', !isVisible); // Adds 'hidden' if isVisible is false
classList.contains()
Check if an element has a specific class.
const element = document.getElementById('myElement');
if (element.classList.contains('active')) {
console.log('Element is active');
} else {
console.log('Element is not active');
}
classList.replace()
Replace an existing class with a new one.
const element = document.getElementById('myElement');
// Replace 'old-class' with 'new-class'
element.classList.replace('old-class', 'new-class');
Practical ClassList Examples
const tabs = document.querySelectorAll('.tab');
const contents = document.querySelectorAll('.tab-content');
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => {
// Remove active class from all tabs
tabs.forEach(t => t.classList.remove('active'));
contents.forEach(c => c.classList.remove('active'));
// Add active class to clicked tab
tab.classList.add('active');
contents[index].classList.add('active');
});
});
const accordionHeaders = document.querySelectorAll('.accordion-header');
accordionHeaders.forEach(header => {
header.addEventListener('click', () => {
const content = header.nextElementSibling;
// Toggle open class
header.classList.toggle('open');
content.classList.toggle('expanded');
});
});
const emailInput = document.getElementById('email');
emailInput.addEventListener('blur', () => {
const isValid = emailInput.value.includes('@');
if (isValid) {
emailInput.classList.remove('error');
emailInput.classList.add('success');
} else {
emailInput.classList.remove('success');
emailInput.classList.add('error');
}
});
const button = document.getElementById('submitBtn');
async function submitForm() {
// Add loading state
button.classList.add('loading', 'disabled');
button.textContent = 'Loading...';
try {
await fetch('/api/submit', { method: 'POST' });
button.classList.remove('loading', 'disabled');
button.classList.add('success');
button.textContent = 'Success!';
} catch (error) {
button.classList.remove('loading');
button.classList.add('error');
button.textContent = 'Error!';
}
}
Best Practices and Performance Tips
1. Minimize DOM Manipulations
DOM operations are expensive. Batch your changes when possible.
// ❌ Bad: Multiple reflows
for (let i = 0; i < 100; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
list.appendChild(li);
}
// ✅ Good: Single reflow
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
fragment.appendChild(li);
}
list.appendChild(fragment);
2. Cache DOM References
Don't query the DOM repeatedly for the same element.
// ❌ Bad
document.getElementById('myElement').classList.add('class1');
document.getElementById('myElement').classList.add('class2');
document.getElementById('myElement').classList.add('class3');
// ✅ Good
const element = document.getElementById('myElement');
element.classList.add('class1', 'class2', 'class3');
3. Use classList Instead of className
The classList API is more maintainable and less error-prone.
// ❌ Avoid
element.className = element.className + ' new-class';
// ✅ Better
element.classList.add('new-class');
4. Event Delegation
Instead of adding listeners to many elements, use delegation.
// ✅ Good: One listener on parent
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
e.target.classList.toggle('selected');
}
});
Frequently Asked Questions
DOM manipulation refers to the process of using JavaScript to dynamically create, modify, or delete HTML elements and their attributes on a web page. It allows developers to make websites interactive by responding to user actions, updating content without page reloads, and creating dynamic user interfaces.
createElement() creates a new DOM element node that you can customize and append to the document, offering better performance and security. innerHTML sets or gets HTML content as a string, which is convenient for adding multiple elements at once but can be slower and poses security risks if used with user-generated content. For creating single elements with attributes and event listeners, use createElement(). For inserting simple HTML structures, innerHTML is acceptable.
textContent gets or sets the text content of an element including hidden elements and is faster because it doesn't trigger reflow. innerText is aware of CSS styling and only returns visible text, making it slower. Best practice: use textContent for better performance unless you specifically need to respect CSS visibility.
Use the classList.contains() method to check if an element has a specific class. For example: element.classList.contains('active') returns true if the element has the class "active" and false otherwise. This is more reliable than checking the className property directly.
Yes, the classList.add() method accepts multiple class names as separate arguments