# JavaScript DOM Manipulation Guide - Complete Reference
## Table of Contents
- [Introduction](#introduction)
- [Understanding the DOM](#understanding-the-dom)
- [Selecting Elements](#selecting-elements)
- [By ID](#by-id)
- [By Class or Tag](#by-class-or-tag)
- [By CSS Selector](#by-css-selector)
- [Other Selection Methods](#other-selection-methods)
- [Working with Element Content](#working-with-element-content)
- [Text Content](#text-content)
- [HTML Content](#html-content)
- [Working with Attributes](#working-with-attributes)
- [Getting and Setting Attributes](#getting-and-setting-attributes)
- [Working with Data Attributes](#working-with-data-attributes)
- [Working with CSS Styles](#working-with-css-styles)
- [Inline Styles](#inline-styles)
- [Computed Styles](#computed-styles)
- [Working with Classes](#working-with-classes)
- [Creating and Removing Elements](#creating-and-removing-elements)
- [Event Handling](#event-handling)
- [Adding Event Listeners](#adding-event-listeners)
- [Event Object](#event-object)
- [Event Propagation](#event-propagation)
- [Event Delegation](#event-delegation)
- [Working with Forms](#working-with-forms)
- [Practical Examples](#practical-examples)
- [Todo List Application](#todo-list-application)
- [Modal Dialog](#modal-dialog)
- [Tabs Component](#tabs-component)
---
## Introduction
The Document Object Model (DOM) is a programming interface for web documents. It represents the page so that programs can change the document structure, style, and content. JavaScript interacts with the DOM to create dynamic web pages.
---
## Understanding the DOM
```javascript
// The DOM tree structure
// document (root)
// └── html
// ├── head
// │ ├── title
// │ └── meta
// └── body
// ├── header
// ├── main
// │ ├── section
// │ └── article
// └── footer
// Every part of the page is a "node" in this tree
console.log(document); // The entire document
console.log(document.body); // The body element
console.log(document.head); // The head element
console.log(document.documentElement); // The html element
```
---
## Selecting Elements
### By ID
```javascript
// Get element by ID - returns single element or null
const header = document.getElementById('header');
const main = document.getElementById('main-content');
const nonExistent = document.getElementById('does-not-exist');
console.log(header); // ...
console.log(nonExistent); // null
```
### By Class or Tag
```javascript
// Get elements by class name - returns HTMLCollection (live)
const buttons = document.getElementsByClassName('btn');
console.log(buttons.length); // Number of elements with class "btn"
// Get elements by tag name - returns HTMLCollection (live)
const paragraphs = document.getElementsByTagName('p');
const divs = document.getElementsByTagName('div');
console.log(paragraphs.length); // Number of
elements
```
### By CSS Selector
```javascript
// querySelector - returns first match or null
const firstButton = document.querySelector('.btn');
const firstInput = document.querySelector('input[type="email"]');
const navItem = document.querySelector('#nav li.active');
// querySelectorAll - returns NodeList of all matches
const allButtons = document.querySelectorAll('.btn');
const allSections = document.querySelectorAll('section');
const allItems = document.querySelectorAll('#nav li');
// NodeList is NOT live - it's a snapshot
console.log(allButtons.length); // Number of buttons
// Loop through NodeList
allButtons.forEach(btn => {
console.log(btn.textContent);
});
// Convert to array
const buttonsArray = Array.from(allButtons);
```
### Other Selection Methods
```javascript
// Get first child element (skipping text nodes)
const firstChild = element.firstElementChild;
// Get last child element
const lastChild = element.lastElementChild;
// Get parent element
const parent = element.parentElement;
// Get siblings
const nextSibling = element.nextElementSibling;
const prevSibling = element.previousElementSibling;
// Get children
const children = element.children; // HTMLCollection
// Closest ancestor matching selector
const ancestor = element.closest('.container');
```
---
## Working with Element Content
### Text Content
```javascript
// textContent - gets/sets ALL text content (including hidden)
const element = document.getElementById('myElement');
console.log(element.textContent); // Get all text
element.textContent = 'New text content'; // Set text (escapes HTML)
// innerText - gets/sets VISIBLE text (respects CSS)
console.log(element.innerText); // Get visible text
element.innerText = 'Visible text'; // Set visible text
// Difference:
const hidden = document.createElement('div');
hidden.style.display = 'none';
hidden.textContent = 'Hidden text';
document.body.appendChild(hidden);
console.log(hidden.textContent); // "Hidden text"
console.log(hidden.innerText); // "" (empty - not visible)
```
### HTML Content
```javascript
// innerHTML - gets/sets HTML content (parses as HTML)
const container = document.getElementById('container');
console.log(container.innerHTML); // Get HTML
container.innerHTML = '
New paragraph
'; // Set HTML
// Be careful with innerHTML - can overwrite event listeners
// This removes all existing children and their handlers
// insertAdjacentHTML - insert HTML at specific position
element.insertAdjacentHTML('beforebegin', '
Before element
');
element.insertAdjacentHTML('afterbegin', '
First child
');
element.insertAdjacentHTML('beforeend', '
Last child
');
element.insertAdjacentHTML('afterend', '
After element
');
// outerHTML - gets/sets entire element including the element itself
console.log(element.outerHTML); // Get element as HTML string
element.outerHTML = '
New element
'; // Replace entire element
```
---
## Working with Attributes
### Getting and Setting Attributes
```javascript
const input = document.querySelector('input[type="text"]');
// getAttribute - get attribute value
console.log(input.getAttribute('id'));
console.log(input.getAttribute('placeholder'));
// setAttribute - set attribute value
input.setAttribute('placeholder', 'Enter your name');
input.setAttribute('disabled', true); // Add boolean attribute
// hasAttribute - check if attribute exists
if (input.hasAttribute('required')) {
console.log('Input is required');
}
// removeAttribute - remove attribute
input.removeAttribute('disabled');
// Direct property access for common attributes
input.value = 'Hello'; // Get/set value
input.disabled = true; // Get/set disabled
input.checked = true; // Get/set checked (checkboxes)
input.id = 'myInput'; // Get/set id
input.className = 'btn primary'; // Get/set class
```
### Working with Data Attributes
```javascript
const element = document.querySelector('.user');
// data-* attributes become dataset properties
element.dataset.userId = '12345';
element.dataset.role = 'admin';
element.dataset['customField'] = 'value';
// Remove data attribute
delete element.dataset.userId;
// Access all data attributes
console.log(element.dataset); // DOMStringMap object
// HTML:
// JS: element.dataset.userId → "123"
// JS: element.dataset.name → "Alice"
```
---
## Working with CSS Styles
### Inline Styles
```javascript
const element = document.getElementById('myElement');
// Set individual styles
element.style.color = 'red';
element.style.backgroundColor = '#f0f0f0';
element.style.fontSize = '16px';
element.style.display = 'none';
element.style.border = '1px solid black';
// CSS properties with hyphens become camelCase
element.style.borderRadius = '5px';
element.style.backgroundImage = 'url("image.jpg")';
// Get inline style
console.log(element.style.color); // Only returns inline styles
// Set multiple styles at once using CSSText
element.style.cssText = 'color: red; background: blue; padding: 10px;';
// Or use setProperty
element.style.setProperty('color', 'blue');
element.style.setProperty('--custom-color', 'green'); // CSS variables
```
### Computed Styles
```javascript
const element = document.getElementById('myElement');
// getComputedStyle - get computed styles (from all sources)
const styles = getComputedStyle(element);
console.log(styles.color); // RGB color
console.log(styles.fontSize); // Computed font size
console.log(styles.display); // Display property
console.log(styles.backgroundColor); // Background color
// Get specific property
const width = getComputedStyle(element).width;
const height = getComputedStyle(element).height;
// Get CSS variable
const customColor = getComputedStyle(element).getPropertyValue('--custom-color');
// Get pseudo-element style
const beforeStyle = getComputedStyle(element, ':before');
console.log(beforeStyle.content);
```
---
## Working with Classes
```javascript
const element = document.getElementById('myElement');
// classList - provides methods for working with classes
element.classList.add('active'); // Add class
element.classList.remove('hidden'); // Remove class
element.classList.toggle('selected'); // Toggle class
const hasClass = element.classList.contains('active'); // Check class
// Add multiple classes
element.classList.add('btn', 'btn-primary', 'large');
// Remove multiple classes
element.classList.remove('btn', 'btn-small');
// Replace class
element.classList.replace('old-class', 'new-class');
// Get class count
console.log(element.classList.length);
// Access class by index
console.log(element.classList[0]);
// className - get/set entire class attribute
console.log(element.className); // Get all classes
element.className = 'new-classes'; // Replaces all classes
```
---
## Creating and Removing Elements
```javascript
// Create new element
const newDiv = document.createElement('div');
newDiv.id = 'new-div';
newDiv.classList.add('container');
newDiv.textContent = 'Hello World';
// Add element to DOM
document.body.appendChild(newDiv); // Add as last child
// Or insert at specific position
const container = document.getElementById('container');
container.appendChild(newDiv);
// insertBefore - insert before a reference node
container.insertBefore(newDiv, container.firstChild);
// Modern insertion methods
container.append(newDiv, 'Text node'); // Multiple items
container.prepend(newDiv); // Insert as first child
container.before(newDiv); // Insert before element
container.after(newDiv); // Insert after element
// Clone element
const clone = originalElement.cloneNode(true); // Deep clone (with children)
const shallowClone = originalElement.cloneNode(false); // Just the element
// Remove element
newDiv.remove(); // Modern method
container.removeChild(newDiv); // Old method
// Replace element
container.replaceChild(newElement, oldElement);
container.replaceWith(newElement); // Modern method
// Creating document fragments (for performance)
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const item = document.createElement('div');
item.textContent = `Item ${i}`;
fragment.appendChild(item);
}
container.appendChild(fragment); // Single reflow
```
---
## Event Handling
### Adding Event Listeners
```javascript
const button = document.getElementById('myButton');
// addEventListener - recommended way to add events
function handleClick(event) {
console.log('Button clicked!');
}
button.addEventListener('click', handleClick);
// Add multiple event listeners
button.addEventListener('click', () => console.log('First handler'));
button.addEventListener('click', () => console.log('Second handler'));
// Remove event listener (needs named function)
button.removeEventListener('click', handleClick);
// Options for addEventListener
button.addEventListener('click', handler, {
capture: false, // Use capture phase
once: true, // Remove after first trigger
passive: true // Promise not to call preventDefault
});
// One-time event listener
button.addEventListener('click', () => console.log('Only once'), { once: true });
```
### Event Object
```javascript
element.addEventListener('click', function(event) {
// event.type - type of event
console.log(event.type); // "click"
// event.target - element that triggered event
console.log(event.target); // The clicked element
// event.currentTarget - element with listener
console.log(event.currentTarget); // The element with addEventListener
// event.preventDefault() - prevent default behavior
event.preventDefault();
// event.stopPropagation() - stop event from bubbling
event.stopPropagation();
// Mouse event properties
console.log(event.clientX, event.clientY); // Mouse position
console.log(event.pageX, event.pageY); // Position relative to document
// Keyboard event properties
console.log(event.key); // Key pressed
console.log(event.code); // Physical key code
console.log(event.shiftKey); // Was shift held?
});
// Different events
element.addEventListener('click', handler); // Mouse click
element.addEventListener('dblclick', handler); // Double click
element.addEventListener('mouseenter', handler); // Mouse enters
element.addEventListener('mouseleave', handler); // Mouse leaves
element.addEventListener('mouseover', handler); // Mouse enters (bubbles)
element.addEventListener('mouseout', handler); // Mouse leaves (bubbles)
input.addEventListener('input', handler); // Value changes
input.addEventListener('change', handler); // Value changes (on blur)
input.addEventListener('focus', handler); // Gets focus
input.addEventListener('blur', handler); // Loses focus
document.addEventListener('keydown', handler); // Key pressed
document.addEventListener('keyup', handler); // Key released
form.addEventListener('submit', handler); // Form submitted
```
### Event Propagation
```javascript
// Event phases: capture → target → bubble
// By default, listeners are in bubble phase
const parent = document.querySelector('.parent');
const child = document.querySelector('.child');
const grandchild = document.querySelector('.grandchild');
// Stop propagation - prevent event from reaching other elements
grandchild.addEventListener('click', function(event) {
event.stopPropagation(); // Parent won't hear the click
console.log('Grandchild clicked');
});
parent.addEventListener('click', function(event) {
console.log('Parent clicked');
});
// Stop immediate propagation - stop others on same element
grandchild.addEventListener('click', function(event) {
event.stopImmediatePropagation();
console.log('First handler');
});
grandchild.addEventListener('click', function(event) {
console.log('Second handler - won\'t run');
});
// Capture phase - event goes from root down to target
parent.addEventListener('click', function(event) {
console.log('Capture phase');
}, { capture: true });
// Bubble phase - event goes from target up to root (default)
parent.addEventListener('click', function(event) {
console.log('Bubble phase');
});
```
### Event Delegation
```javascript
// Instead of adding listeners to each item, add to parent
const list = document.getElementById('todo-list');
// Add single listener to parent
list.addEventListener('click', function(event) {
// Check if clicked element is an item
if (event.target.matches('.todo-item')) {
// Handle the item
event.target.classList.toggle('completed');
}
// Handle delete button within item
if (event.target.matches('.delete-btn')) {
event.target.parentElement.remove();
}
});
// Dynamically added items automatically work
const newItem = document.createElement('li');
newItem.className = 'todo-item';
newItem.textContent = 'New task';
list.appendChild(newItem); // Works without adding new listener
```
---
## Working with Forms
```javascript
const form = document.getElementById('myForm');
// Get form data
const formData = new FormData(form);
const data = Object.fromEntries(formData);
// Or manually
const name = form.name.value;
const email = form.email.value;
const password = form.password.value;
// Checkbox
const subscribe = form.subscribe.checked;
// Radio buttons
const gender = form.gender.value; // Selected radio's value
// Select dropdown
const country = form.country.value; // Selected option value
const selectedOption = form.country.options[form.country.selectedIndex];
// Validate form
function validateForm(form) {
const errors = [];
if (!form.name.value.trim()) {
errors.push('Name is required');
}
if (!form.email.value.includes('@')) {
errors.push('Valid email is required');
}
if (form.password.value.length < 8) {
errors.push('Password must be at least 8 characters');
}
return errors;
}
// Handle form submission
form.addEventListener('submit', function(event) {
event.preventDefault(); // Prevent page reload
const errors = validateForm(form);
if (errors.length > 0) {
console.log('Errors:', errors);
return;
}
// Submit form data
console.log('Form is valid!');
// form.submit(); // Actually submit (if not using fetch)
});
// Reset form
form.reset();
```
---
## Practical Examples
### Todo List Application
```javascript
class TodoList {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.todos = JSON.parse(localStorage.getItem('todos')) || [];
this.init();
}
init() {
this.render();
this.setupEventListeners();
}
render() {
this.container.innerHTML = this.todos.map((todo, index) => `