HTML
10 / 12

HTML APIs & Web Platform

HTML APIs & Web Platform

Web Storage

// localStorage — persists until explicitly cleared (survives browser restarts)
localStorage.setItem('user_prefs', JSON.stringify({ theme: 'dark', lang: 'en' }));
const prefs = JSON.parse(localStorage.getItem('user_prefs') ?? '{}');
localStorage.removeItem('user_prefs');
localStorage.clear();  // clears ALL keys for this origin

// sessionStorage — cleared when tab is closed
sessionStorage.setItem('draft', JSON.stringify(formData));
const draft = JSON.parse(sessionStorage.getItem('draft') ?? 'null');
sessionStorage.removeItem('draft');

// Both have the same API. Key differences:
// localStorage: 5-10MB limit, shared across all tabs for the same origin
// sessionStorage: 5-10MB limit, isolated per tab

// Listen for storage events (fires in OTHER tabs, not the one that changed it)
window.addEventListener('storage', (event) => {
  console.log('Key changed:', event.key);
  console.log('Old value:', event.oldValue);
  console.log('New value:', event.newValue);
});

History API

// Navigate without page reload
history.pushState({ page: 'about' }, '', '/about');    // adds to history
history.replaceState({ page: 'home' }, '', '/');        // replaces current entry

// Go back/forward programmatically
history.back();
history.forward();
history.go(-2);  // go back 2 steps

// Handle browser back/forward button
window.addEventListener('popstate', (event) => {
  console.log('Navigated to state:', event.state);
  renderPage(event.state);
});

// Current URL info
const url = new URL(window.location.href);
console.log(url.pathname);    // /about
console.log(url.searchParams.get('q'));  // query param
url.searchParams.set('page', '2');
history.pushState({}, '', url.toString());

Intersection Observer

// Detect when elements enter/leave the viewport
// Use for: lazy loading, infinite scroll, animation triggers, analytics

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('visible');
      entry.target.src = entry.target.dataset.src;  // lazy load image
      observer.unobserve(entry.target);  // stop observing after first trigger
    }
  });
}, {
  root: null,          // viewport
  rootMargin: '200px', // start loading 200px before entering viewport
  threshold: 0.1,      // fire when 10% of element is visible
});

// Observe all lazy images
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));

// Infinite scroll
const sentinel = document.querySelector('#load-more');
const infiniteObserver = new IntersectionObserver((entries) => {
  if (entries[0].isIntersecting) loadMoreItems();
}, { threshold: 1.0 });
infiniteObserver.observe(sentinel);

MutationObserver

// Watch for DOM changes (added/removed nodes, attribute changes)
const observer = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
    if (mutation.type === 'childList') {
      mutation.addedNodes.forEach(node => {
        if (node.nodeType === Node.ELEMENT_NODE) {
          console.log('Element added:', node.tagName);
        }
      });
    }
    if (mutation.type === 'attributes') {
      console.log('Attribute changed:', mutation.attributeName);
    }
  });
});

observer.observe(document.body, {
  childList: true,    // child node additions/removals
  subtree: true,      // observe all descendants
  attributes: true,   // attribute changes
  attributeFilter: ['class', 'data-theme'],  // only these attributes
  characterData: true, // text content changes
});

// Disconnect when done
observer.disconnect();

Clipboard API

// Write to clipboard
async function copyToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    showToast('Copied!');
  } catch (err) {
    // Fallback for older browsers
    const el = document.createElement('textarea');
    el.value = text;
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
  }
}

// Read from clipboard
async function readFromClipboard() {
  const text = await navigator.clipboard.readText();
  return text;
}

// Copy image to clipboard
async function copyImage(blob) {
  await navigator.clipboard.write([
    new ClipboardItem({ 'image/png': blob })
  ]);
}

Drag & Drop API

// Make element draggable
const draggable = document.querySelector('.draggable');
draggable.setAttribute('draggable', 'true');

draggable.addEventListener('dragstart', (e) => {
  e.dataTransfer.setData('text/plain', e.target.id);
  e.dataTransfer.effectAllowed = 'move';
});

// Drop target
const dropZone = document.querySelector('.drop-zone');

dropZone.addEventListener('dragover', (e) => {
  e.preventDefault();  // allow drop
  e.dataTransfer.dropEffect = 'move';
  dropZone.classList.add('drag-over');
});

dropZone.addEventListener('dragleave', () => {
  dropZone.classList.remove('drag-over');
});

dropZone.addEventListener('drop', (e) => {
  e.preventDefault();
  const id = e.dataTransfer.getData('text/plain');
  const dragged = document.getElementById(id);
  dropZone.appendChild(dragged);
  dropZone.classList.remove('drag-over');
});

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free