JavaScript logoJavaScriptBEGINNER

DOM Manipulation

DOM manipulation cheat sheet with selectors, event handling, element creation, traversal, and vanilla JavaScript code examples.

7 min read
domjavascripthtmlbrowserevents

Sign in to mark items as known and track your progress.

Sign in

Element Selection

Query Selectors

Select elements using CSS selectors for flexible element targeting

javascript
// Select first matching element
const element = document.querySelector('.class-name')
const element = document.querySelector('#id')
const element = document.querySelector('[data-id="123"]')

// Select all matching elements (returns NodeList)
const elements = document.querySelectorAll('.class-name')
const elements = document.querySelectorAll('div.active')
const elements = document.querySelectorAll('[type="checkbox"]:checked')

// Convert NodeList to Array
const array = Array.from(document.querySelectorAll('.item'))
const array = [...document.querySelectorAll('.item')]
💡 querySelector uses CSS selector syntax
⚡ getElementById is faster for IDs
📌 querySelectorAll returns NodeList, not Array
✅ Always check if element exists before using

Get Element Methods

Traditional DOM methods for selecting elements by ID, class, or tag

javascript
// Get single element by ID (fastest)
const element = document.getElementById('header')

// Get elements by class (returns live HTMLCollection)
const elements = document.getElementsByClassName('item')

// Get elements by tag name (returns live HTMLCollection)
const elements = document.getElementsByTagName('div')

// Get elements by name attribute (forms)
const elements = document.getElementsByName('email')
💡 getElementById is the fastest selection method
⚠️ HTMLCollection is live and updates automatically
📌 No # or . prefix needed for getElementById/ClassName
✅ Convert to array for array methods

Creating Elements

createElement & cloneNode

Create new elements or clone existing ones programmatically

javascript
// Create new element
const div = document.createElement('div')
div.className = 'card'
div.textContent = 'Hello World'

// Clone existing element
const original = document.querySelector('.card')
const clone = original.cloneNode(true)  // true = deep clone

// Create with attributes
const link = document.createElement('a')
link.href = 'https://example.com'
link.textContent = 'Click me'
link.target = '_blank'
💡 Set properties before adding to DOM for performance
⚡ Use DocumentFragment for adding multiple elements
📌 cloneNode(true) for deep clone with children
✅ Template elements are great for complex HTML

innerHTML & insertAdjacentHTML

Insert HTML content directly into elements using string templates

javascript
// Set innerHTML (replaces all content)
element.innerHTML = '<p>New content</p>'

// Append HTML (preserves existing)
element.insertAdjacentHTML('beforeend', '<p>Added paragraph</p>')

// Insert at different positions
element.insertAdjacentHTML('beforebegin', '<p>Before element</p>')
element.insertAdjacentHTML('afterbegin', '<p>First child</p>')
element.insertAdjacentHTML('beforeend', '<p>Last child</p>')
element.insertAdjacentHTML('afterend', '<p>After element</p>')
⚠️ innerHTML can cause XSS vulnerabilities with user input
💡 insertAdjacentHTML preserves existing content and event listeners
⚡ Building HTML strings is faster for many elements
✅ Use textContent for user input to prevent XSS

Modifying Elements

Text & HTML Content

Modify the text and HTML content of elements safely

javascript
// Text content (safe, escapes HTML)
element.textContent = 'Hello World'
const text = element.textContent

// Inner text (respects styling)
element.innerText = 'Visible text only'
const visible = element.innerText

// HTML content (parses HTML)
element.innerHTML = '<strong>Bold text</strong>'
const html = element.innerHTML

// Outer HTML (includes element itself)
element.outerHTML = '<div>Replacement</div>'
💡 textContent is safe from XSS attacks
⚠️ innerHTML removes existing event listeners
📌 innerText respects CSS visibility
✅ Always use textContent for user input

Attributes & Properties

Get, set, and remove HTML attributes and DOM properties

javascript
// Set attribute
element.setAttribute('data-id', '123')
element.setAttribute('disabled', '')

// Get attribute
const id = element.getAttribute('data-id')
const href = link.getAttribute('href')

// Remove attribute
element.removeAttribute('disabled')
element.removeAttribute('data-id')

// Check attribute
if (element.hasAttribute('disabled')) {
  // Element is disabled
}
💡 Properties are faster than attributes for common values
📌 Data attributes are accessed via dataset property
⚠️ Attribute values are always strings
✅ Use properties for boolean values (checked, disabled)

Styling & Classes

classList Methods

Manage CSS classes on elements with the classList API

javascript
// Add class
element.classList.add('active')
element.classList.add('highlight', 'large')

// Remove class
element.classList.remove('active')
element.classList.remove('highlight', 'large')

// Toggle class
element.classList.toggle('visible')

// Check class
if (element.classList.contains('active')) {
  // Has active class
}

// Replace class
element.classList.replace('old-class', 'new-class')
💡 classList is more efficient than className manipulation
⚡ Can add/remove multiple classes at once
📌 toggle() returns true if class was added, false if removed
✅ classList.contains() is cleaner than string searching

Inline Styles

Directly manipulate element styles through the style property

javascript
// Set individual styles
element.style.color = 'red'
element.style.backgroundColor = '#f0f0f0'
element.style.fontSize = '16px'

// Set multiple styles
Object.assign(element.style, {
  color: 'blue',
  fontSize: '20px',
  margin: '10px'
})

// Remove style
element.style.color = ''
element.style.removeProperty('background-color')

// Get computed styles
const styles = window.getComputedStyle(element)
const color = styles.getPropertyValue('color')
💡 Style properties use camelCase (backgroundColor)
⚠️ Inline styles have high specificity
📌 getComputedStyle returns resolved values
✅ Prefer CSS classes over inline styles

DOM Traversal

Parent & Child Navigation

Navigate between parent and child elements in the DOM tree

javascript
// Parent access
const parent = element.parentElement
const parentNode = element.parentNode

// Children access
const children = element.children  // HTMLCollection
const childNodes = element.childNodes  // NodeList (includes text)

// First and last child
const first = element.firstElementChild
const last = element.lastElementChild

// Check for children
if (element.hasChildNodes()) {
  // Has child nodes
}
💡 children returns only elements, childNodes includes text
📌 closest() is great for event delegation
⚡ parentElement is null for document
✅ Use contains() to check relationships

Sibling Navigation

Navigate between sibling elements at the same DOM level

javascript
// Next sibling
const next = element.nextElementSibling
const nextNode = element.nextSibling  // Can be text

// Previous sibling
const prev = element.previousElementSibling
const prevNode = element.previousSibling

// All siblings
const parent = element.parentElement
const siblings = Array.from(parent.children)
  .filter(child => child !== element)
💡 ElementSibling properties skip text nodes
📌 Sibling properties return null at boundaries
⚡ Cache parent.children for multiple operations
✅ Filter self out when getting all siblings

Adding & Removing

Adding Elements

Add elements to the DOM using various insertion methods

javascript
// Append as last child
parent.appendChild(element)
parent.append(element, 'text', element2)

// Prepend as first child
parent.prepend(element)
parent.insertBefore(element, parent.firstChild)

// Insert at specific position
parent.insertBefore(newElement, referenceElement)

// Insert adjacent to element
element.insertAdjacentElement('afterend', newElement)
💡 appendChild moves elements, doesn't copy
⚡ Use DocumentFragment for batch inserts
📌 append() can add multiple items and text
✅ insertAdjacentElement preserves element position

Removing Elements

Remove elements from the DOM or replace them with new ones

javascript
// Remove element (modern)
element.remove()

// Remove child (classic)
parent.removeChild(child)

// Replace element
oldElement.replaceWith(newElement)
parent.replaceChild(newElement, oldElement)

// Clear all children
parent.innerHTML = ''
parent.textContent = ''
💡 remove() is simpler than removeChild()
⚠️ innerHTML = "" removes event listeners
📌 replaceWith() can replace with multiple items
✅ Always check element exists before removing

Events - Basics

Event Listeners

Attach and remove event handlers to respond to user interactions

javascript
// Add event listener
element.addEventListener('click', handleClick)

// With options
element.addEventListener('scroll', handleScroll, {
  passive: true,
  once: true
})

// Remove event listener
element.removeEventListener('click', handleClick)

// Event handler function
function handleClick(event) {
  console.log('Clicked!', event.target)
}
💡 Named functions can be removed, anonymous cannot
⚡ Use passive: true for scroll/touch events
📌 Arrow functions don't have their own "this"
✅ Use AbortController for multiple listener cleanup

Event Object

Access event properties and control event behavior

javascript
// Event properties
function handleClick(event) {
  event.target          // Element that triggered event
  event.currentTarget   // Element with listener
  event.type           // Event type (e.g., 'click')
  event.timeStamp      // When event occurred
  
  // Prevent default action
  event.preventDefault()
  
  // Stop propagation
  event.stopPropagation()
}
💡 target vs currentTarget is important for delegation
⚠️ preventDefault doesn't stop propagation
📌 Use event.key for keyboard events, not keyCode
✅ Check cancelable before calling preventDefault

Events - Advanced

Event Delegation

Handle events efficiently using event bubbling and delegation

javascript
// Delegate events to parent
document.addEventListener('click', (event) => {
  if (event.target.matches('.button')) {
    // Handle button click
  }
})

// Closest for complex structures
list.addEventListener('click', (event) => {
  const item = event.target.closest('.item')
  if (item) {
    // Handle item click
  }
})
💡 Delegation works for dynamically added elements
⚡ One listener is better than many
📌 Use closest() for complex component structures
✅ Check event.target existence in delegated handlers

Custom Events

Create and dispatch custom events for component communication

javascript
// Create custom event
const event = new CustomEvent('user-login', {
  detail: { userId: 123, username: 'john' },
  bubbles: true
})

// Dispatch event
element.dispatchEvent(event)

// Listen for custom event
element.addEventListener('user-login', (event) => {
  console.log('User logged in:', event.detail)
})
💡 CustomEvent can carry data in detail property
📌 Namespace events to avoid conflicts
⚡ Use bubbles: true for component communication
✅ Document can serve as a global event bus

Forms

Form Elements & Data

Access and manipulate form elements and their values

javascript
// Get form and elements
const form = document.getElementById('myForm')
const input = form.elements['username']
const inputs = form.elements  // All form controls

// Get values
const value = input.value
const checked = checkbox.checked
const selected = select.value

// FormData API
const formData = new FormData(form)
const username = formData.get('username')
💡 FormData makes form handling much easier
📌 form.elements provides easy access to inputs
⚡ Use checkValidity() for HTML5 validation
✅ Always preventDefault() on form submit for SPA

Form Events

Handle form-specific events for validation and interaction

javascript
// Form events
form.addEventListener('submit', handleSubmit)
form.addEventListener('reset', handleReset)

// Input events
input.addEventListener('input', handleInput)     // On every change
input.addEventListener('change', handleChange)   // On blur if changed
input.addEventListener('focus', handleFocus)
input.addEventListener('blur', handleBlur)

// Validation events
input.addEventListener('invalid', handleInvalid)
💡 input event for real-time, change for final value
📌 focusin/focusout bubble, focus/blur don't
⚠️ Prevent invalid event to show custom messages
✅ Debounce validation for better performance

Modern DOM APIs

Intersection Observer

Efficiently detect when elements enter or leave the viewport

javascript
// Create observer
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('visible')
    }
  })
})

// Observe elements
document.querySelectorAll('.lazy').forEach(el => {
  observer.observe(el)
})

// Stop observing
observer.unobserve(element)
observer.disconnect()
💡 More efficient than scroll event listeners
⚡ Great for lazy loading and animations
📌 Can observe multiple elements with one observer
✅ Always disconnect when done observing

Mutation Observer

Watch for changes to the DOM tree and element attributes

javascript
// Create observer
const observer = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
    console.log('Type:', mutation.type)
    console.log('Target:', mutation.target)
  })
})

// Observe element
observer.observe(element, {
  childList: true,      // Child changes
  attributes: true,     // Attribute changes
  subtree: true        // All descendants
})

// Stop observing
observer.disconnect()
💡 Can detect any DOM change
⚠️ Be careful with subtree: true on large DOMs
📌 Use takeRecords() to get pending mutations
✅ Always disconnect when no longer needed