DOM Manipulation in JavaScript

What is the DOM?

The Document Object Model (DOM) is a programming interface for web documents. It represents the page as nodes and objects that can be manipulated with JavaScript.

Selecting DOM Elements

By ID

const element = document.getElementById('myId');

By Class Name

const elements = document.getElementsByClassName('myClass');
// Returns HTMLCollection (array-like object)

By Tag Name

const elements = document.getElementsByTagName('div');
// Returns HTMLCollection

CSS Selectors

// Select first matching element
const element = document.querySelector('.myClass');

// Select all matching elements
const elements = document.querySelectorAll('div.myClass');
// Returns NodeList

Creating and Modifying Elements

Creating Elements

// Create a new element
const div = document.createElement('div');

// Create text node
const text = document.createTextNode('Hello World');

// Append text to div
div.appendChild(text);

Modifying Element Content

// Set text content
element.textContent = 'New text content';

// Set HTML content (careful with XSS)
element.innerHTML = '<span>New HTML content</span>';

// Set HTML content safely
element.innerHTML = '';
const span = document.createElement('span');
span.textContent = 'New HTML content';
element.appendChild(span);

Modifying Attributes

// Get attribute
const value = element.getAttribute('data-id');

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

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

// Check if attribute exists
const hasAttribute = element.hasAttribute('data-id');

// Using properties for common attributes
element.id = 'newId';
element.className = 'newClass';
element.href = 'https://example.com';

Manipulating DOM Structure

Adding Elements

// Append child (at the end)
parent.appendChild(child);

// Insert before another element
parent.insertBefore(newChild, referenceChild);

// Modern methods
parent.append(child1, child2, 'text'); // Multiple nodes and text
parent.prepend(child); // Insert at beginning
referenceElement.before(newElement); // Insert before
referenceElement.after(newElement); // Insert after

Removing Elements

// Remove child from parent
parent.removeChild(child);

// Modern method (self-removal)
element.remove();

Replacing Elements

// Replace child
parent.replaceChild(newChild, oldChild);

// Modern method
oldElement.replaceWith(newElement);

Cloning Elements

// Clone without descendants
const clone = element.cloneNode(false);

// Clone with all descendants
const deepClone = element.cloneNode(true);

Manipulating CSS

Working with Classes

// Add class
element.classList.add('active');

// Remove class
element.classList.remove('active');

// Toggle class (add if absent, remove if present)
element.classList.toggle('active');

// Check if class exists
const hasClass = element.classList.contains('active');

// Replace class
element.classList.replace('old', 'new');

Inline Styles

// Get computed style
const style = window.getComputedStyle(element);
const color = style.color;

// Set inline style
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.cssText = 'color: red; background-color: blue;';

// Remove inline style
element.style.color = '';

Event Handling

Adding Event Listeners

element.addEventListener('click', function(event) {
  console.log('Element clicked!');
});

// With event object
element.addEventListener('click', function(event) {
  console.log('Clicked at:', event.clientX, event.clientY);
  event.preventDefault(); // Prevent default behavior
  event.stopPropagation(); // Stop event bubbling
});

// With options
element.addEventListener('click', handler, {
  once: true, // Run only once
  capture: true, // Use capture phase
  passive: true // Never call preventDefault()
});

Removing Event Listeners

function handler(event) {
  console.log('Handled!');
}

// Add listener
element.addEventListener('click', handler);

// Remove listener (must use same function reference)
element.removeEventListener('click', handler);

Event Delegation

// Instead of adding listeners to each button
document.getElementById('buttonContainer').addEventListener('click', function(event) {
  // Check if clicked element is a button
  if (event.target.tagName === 'BUTTON') {
    console.log('Button clicked:', event.target.textContent);
  }
});

DOM Traversal

Parent Relationships

// Parent node
const parent = element.parentNode;

// Parent element (skips non-element nodes)
const parentElement = element.parentElement;

Child Relationships

// All child nodes (including text nodes, comments)
const childNodes = element.childNodes;

// Child elements only
const children = element.children;

// First and last child
const firstChild = element.firstChild; // May be text node
const firstElement = element.firstElementChild;
const lastChild = element.lastChild;
const lastElement = element.lastElementChild;

Sibling Relationships

// Next sibling
const nextSibling = element.nextSibling; // May be text node
const nextElement = element.nextElementSibling;

// Previous sibling
const prevSibling = element.previousSibling;
const prevElement = element.previousElementSibling;

Performance Considerations

DOM Manipulation Best Practices

  1. Minimize DOM access: Cache DOM references

    // Bad: Repeated DOM access
    for (let i = 0; i < 1000; i++) {
      document.getElementById('result').innerHTML += i + ', ';
    }
    
    // Good: Cache the reference
    const result = document.getElementById('result');
    let content = '';
    for (let i = 0; i < 1000; i++) {
      content += i + ', ';
    }
    result.innerHTML = content;
  2. Use document fragments for batch insertions

    const fragment = document.createDocumentFragment();
    for (let i = 0; i < 1000; i++) {
      const li = document.createElement('li');
      li.textContent = `Item ${i}`;
      fragment.appendChild(li);
    }
    document.getElementById('myList').appendChild(fragment);
  3. Reduce reflows and repaints

    // Bad: Multiple reflows
    const div = document.getElementById('myDiv');
    div.style.width = '100px';
    div.style.height = '100px';
    div.style.marginTop = '20px';
    
    // Good: Batch style changes
    const div = document.getElementById('myDiv');
    div.style.cssText = 'width: 100px; height: 100px; margin-top: 20px;';
    
    // Or use classes
    div.classList.add('my-styled-div');

Modern DOM APIs

Intersection Observer

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('Element is visible in viewport');
      entry.target.classList.add('visible');
    }
  });
}, {
  threshold: 0.1 // Trigger when 10% visible
});

observer.observe(document.querySelector('.target'));

Mutation Observer

const observer = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
    if (mutation.type === 'childList') {
      console.log('Child nodes changed');
    } else if (mutation.type === 'attributes') {
      console.log(`${mutation.attributeName} attribute changed`);
    }
  });
});

observer.observe(element, {
  childList: true, // Watch for changes to child elements
  attributes: true, // Watch for attribute changes
  subtree: true // Watch all descendants
});

ResizeObserver

const observer = new ResizeObserver(entries => {
  for (const entry of entries) {
    const { width, height } = entry.contentRect;
    console.log(`Element size: ${width}px × ${height}px`);
  }
});

observer.observe(document.querySelector('.resizable'));

Interview Tips

  • Explain the difference between innerHTML and textContent
  • Describe event bubbling and capturing phases
  • Discuss performance implications of DOM manipulations
  • Explain how to optimize DOM operations for better performance
  • Demonstrate knowledge of modern DOM APIs and their use cases
  • Describe how to implement event delegation and why it’s useful
  • Explain the difference between HTMLCollection and NodeList

Test Your Knowledge

Take a quick quiz to test your understanding of this topic.

Test Your JavaScript Knowledge

Ready to put your skills to the test? Take our interactive JavaScript quiz and get instant feedback on your answers.