DEV Community

Alex Chen
Alex Chen

Posted on

JavaScript DOM Manipulation: The Practical Guide

JavaScript DOM Manipulation: The Practical Guide

Stop reaching for jQuery. Vanilla JS can do everything.

Selecting Elements

// Single element
const el = document.getElementById('myId');
const firstBtn = document.querySelector('.btn'); // CSS selector!

// Multiple elements
const allDivs = document.querySelectorAll('div'); // NodeList (not array!)
const allButtons = document.querySelectorAll('button.primary');

// Convert to real array (for map/filter/reduce)
const buttons = [...document.querySelectorAll('button')];
// or: Array.from(document.querySelectorAll('button'))
Enter fullscreen mode Exit fullscreen mode

Creating Elements

// Create from scratch
const div = document.createElement('div');
div.className = 'card';
div.id = 'card-1';
div.innerHTML = '<h2>Title</h2><p>Content</p>';
div.dataset.userId = '123'; // data-user-id="123"

// Add to page
document.body.appendChild(div);
parentElement.insertBefore(div, referenceElement);

// Create with HTML string (faster for complex structures)
container.insertAdjacentHTML('beforeend', `
  <div class="card" id="card-2">
    <h2>Another Card</h2>
    <p>Created via insertAdjacentHTML</p>
  </div>
`);
Enter fullscreen mode Exit fullscreen mode

Modifying Elements

const el = document.querySelector('#myEl');

// Text & HTML
el.textContent = 'Plain text'; // Escapes HTML
el.innerHTML = '<b>Rich text</b>'; // Parses HTML

// Classes
el.classList.add('active', 'visible');
el.classList.remove('hidden');
el.classList.toggle('open');
el.classList.contains('active'); // true/false

// Styles
el.style.color = 'red';
el.style.backgroundColor = '#333';
el.style.cssText = 'color: red; padding: 10px;'; // Set multiple at once

// Attributes
el.setAttribute('data-id', '456');
el.getAttribute('href');
el.removeAttribute('disabled');

// Data attributes
el.dataset.userId; // "123"
el.dataset.config; // JSON.parse if you stored JSON
Enter fullscreen mode Exit fullscreen mode

Traversing the DOM

const card = document.querySelector('.card');

// Parent
card.parentElement;
card.closest('.container'); // Find ancestor matching selector

// Children
card.children; // Element nodes only
card.childNodes; // All nodes (including text, comments)
card.firstElementChild;
card.lastElementChild;

// Siblings
card.nextElementSibling;
card.previousElementSibling;

// Query within element
card.querySelector('.title');
card.querySelectorAll('.item');
Enter fullscreen mode Exit fullscreen mode

Event Handling

// Basic click
document.querySelector('#btn').addEventListener('click', function(e) {
  console.log('Clicked!', e.target);
});

// Event delegation (one listener for many children)
document.querySelector('#list').addEventListener('click', function(e) {
  if (e.target.matches('li')) {
    console.log('Clicked item:', e.target.textContent);
  }
});

// Common events
element.addEventListener('input', handler);      // Form input change
element.addEventListener('change', handler);     // Blur after edit
element.addEventListener('submit', handler);     // Form submit
element.addEventListener('keydown', handler);    // Key press
element.addEventListener('scroll', handler);     // Scroll position
element.addEventListener('resize', handler);     // Window resize

// Event object properties
function handleClick(e) {
  e.target;        // The clicked element
  e.currentTarget; // The element with the listener
  e.preventDefault(); // Stop default behavior (form submit, link)
  e.stopPropagation(); // Stop event from bubbling up
  e.key;           // Which key was pressed
  e.code;          // Physical key code ('KeyA', 'Enter')
  e.ctrlKey;       // Modifier keys
}
Enter fullscreen mode Exit fullscreen mode

Animations

// CSS transitions (preferred — GPU accelerated)
el.style.transition = 'transform 0.3s ease, opacity 0.3s ease';
el.style.transform = 'translateX(100px)';
el.style.opacity = '0';

// Web Animations API (no library needed!)
el.animate([
  { transform: 'translateX(0)', opacity: 1 },
  { transform: 'translateX(100px)', opacity: 0.5 },
  { transform: 'translateX(0)', opacity: 1 }
], {
  duration: 500,
  iterations: 1,
  easing: 'ease-in-out'
});

// Intersection Observer (scroll animations)
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('visible');
    }
  });
}, { threshold: 0.1 });

document.querySelectorAll('.animate-on-scroll').forEach(el => observer.observe(el));
Enter fullscreen mode Exit fullscreen mode

Common Patterns

Dynamic List Rendering

const users = await fetch('/api/users').then(r => r.json());
const list = document.querySelector('#user-list');

list.innerHTML = users.map(user => `
  <li class="user-item" data-id="${user.id}">
    <strong>${user.name}</strong>
    <span>${user.email}</span>
    <button class="delete-btn">Delete</button>
  </li>
`).join('');

// Event delegation for dynamic content
list.addEventListener('click', async (e) => {
  if (e.target.matches('.delete-btn')) {
    const li = e.target.closest('li');
    const userId = li.dataset.id;
    await fetch(`/api/users/${userId}`, { method: 'DELETE' });
    li.remove();
  }
});
Enter fullscreen mode Exit fullscreen mode

Form Handling

const form = document.querySelector('#myForm');

form.addEventListener('submit', async (e) => {
  e.preventDefault();

  const formData = new FormData(form);
  const data = Object.fromEntries(formData.entries());

  // Or include disabled fields:
  const allData = new FormData(form).entries().reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});

  try {
    const res = await fetch('/api/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    });

    if (!res.ok) throw new Error(`HTTP ${res.status}`);

    showNotification('Saved successfully!', 'success');
    form.reset();
  } catch (err) {
    showNotification(err.message, 'error');
  }
});
Enter fullscreen mode Exit fullscreen mode

Copy to Clipboard

async function copyToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    showCopiedFeedback();
  } catch (err) {
    // Fallback for older browsers
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed';
    textarea.style.opacity = '0';
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand('copy');
    document.body.removeChild(textarea);
  }
}
Enter fullscreen mode Exit fullscreen mode

What's your most-used DOM manipulation pattern?

Follow @armorbreak for more JavaScript content.

Top comments (0)