Last 30 Days
No notifications
The DOM (Document Object Model) is JavaScript's API for reading and changing HTML. This page covers the everyday vanilla toolkit — querySelector, creating and inserting elements, classList/dataset, forms, and event handling (including event delegation, the trick that makes one listener serve thousands of children).
# DOM Manipulation & Events
document.getElementById("main"); // single, by id
document.querySelector(".card.featured"); // first match — CSS selector
document.querySelectorAll("ul li"); // NodeList of all matches
querySelectorAll returns a NodeList (live-ish, iterable, has forEach). Convert with [...nodes] if you need real array methods.el.textContent = "Hello"; // safe — sets text
el.innerHTML = "<b>Hello</b>"; // ⚠️ parses HTML — XSS risk if user input!
el.value; // for inputs
el.checked; // for checkboxes/radiosconst li = document.createElement("li");
li.textContent = "New item";
li.classList.add("done");list.append(li); // at end (accepts text + nodes)
list.prepend(li); // at start
list.insertBefore(li, list.firstChild);
li.remove(); // remove self
li.replaceWith(other);
el.classList.add("active");
el.classList.remove("hidden");
el.classList.toggle("dark");
el.classList.contains("active");
Avoid el.className = "..." — it overwrites everything.el.setAttribute("href", "/about");
el.getAttribute("href");
el.removeAttribute("disabled");// data-* attributes
// HTML: <button data-user-id="42" data-role="admin">
btn.dataset.userId; // "42" (camelCased)
btn.dataset.role; // "admin"
btn.dataset.role = "user";
el.style.backgroundColor = "tomato";
el.style.cssText = "color: white; padding: 8px;";const cs = getComputedStyle(el);
cs.color;
But prefer toggling classes over inline styles in real apps.btn.addEventListener("click", e => {
console.log(e.target); // the actual clicked element
console.log(e.currentTarget); // the element the listener is on
e.preventDefault(); // stop default (e.g. form submit)
e.stopPropagation(); // stop bubbling up
});
Always pair addEventListener with removeEventListener if you'll re-render — or use { once: true }., attach ONE to the parent:
list.addEventListener("click", e => {
const item = e.target.closest("li");
if (!item) return;
console.log("clicked", item.dataset.id);
});
Faster, less memory, works for items added later.form.addEventListener("submit", e => {
e.preventDefault();
const data = new FormData(form);
const obj = Object.fromEntries(data); // { name: "...", email: "..." }
console.log(obj);
});
HTML provides validation: required, type="email", pattern, min/max — let the browser do the checks.// run after the DOM is parsed
document.addEventListener("DOMContentLoaded", init);// element traversal
el.parentElement;
el.children; // HTMLCollection
el.nextElementSibling;
el.closest(".card"); // walk up to nearest matching ancestor
// scrolling
el.scrollIntoView({ behavior: "smooth", block: "start" });
offsetWidth, getBoundingClientRect) force layout — don't interleave with writes inside loops.style.* lines.