Introduction to JavaScript · Lesson 3 of 5
DOM Manipulation & Events
JavaScript DOM Manipulation
The DOM (Document Object Model) is the browser's representation of your HTML as a tree of objects. JavaScript can read and modify it — that's how web pages become interactive.
Selecting Elements
JavaScript
// By ID (returns single element or null)
const title = document.getElementById("main-title");
// CSS selector — first match
const btn = document.querySelector(".submit-btn");
const nav = document.querySelector("nav > ul > li:first-child");
// CSS selector — all matches (returns NodeList, not Array)
const items = document.querySelectorAll(".card");
const inputs = document.querySelectorAll("input[type='text']");
// Convert NodeList to Array for full array methods
const itemsArray = Array.from(items);
// or: [...items]
// Relative selectors
const parent = element.parentElement;
const children = element.children; // HTMLCollection
const firstChild = element.firstElementChild;
const next = element.nextElementSibling;
const prev = element.previousElementSibling;
const closest = element.closest(".container"); // walks up the DOM treeReading and Modifying Content
JavaScript
const el = document.querySelector(".card");
// Text content
el.textContent; // get plain text (no HTML)
el.textContent = "Hello"; // set text (escapes HTML — safe)
// HTML content
el.innerHTML; // get HTML string
el.innerHTML = "<strong>Bold</strong>"; // set HTML (careful: XSS risk if user input)
el.outerHTML; // includes the element itself
// Form input values
const input = document.querySelector("#username");
input.value; // get current value
input.value = "Asma"; // set valueWorking with Attributes
JavaScript
const link = document.querySelector("a");
// Standard attributes
link.href;
link.href = "https://example.com";
// Any attribute
link.getAttribute("data-id"); // get
link.setAttribute("data-id", "42"); // set
link.removeAttribute("disabled"); // remove
link.hasAttribute("disabled"); // check
// Data attributes
const card = document.querySelector(".card");
card.dataset.userId; // reads data-user-id attribute
card.dataset.category = "electronics"; // sets data-categoryCSS Classes
JavaScript
const el = document.querySelector(".btn");
// classList API (preferred over className)
el.classList.add("active"); // add
el.classList.remove("disabled"); // remove
el.classList.toggle("open"); // add if absent, remove if present
el.classList.toggle("open", true); // force add
el.classList.toggle("open", false); // force remove
el.classList.contains("active"); // check
el.classList.replace("old", "new"); // replace
// Replace whole class string (rarely needed)
el.className = "btn btn-primary";Inline Styles
JavaScript
const el = document.querySelector(".box");
el.style.backgroundColor = "blue"; // camelCase for hyphenated properties
el.style.fontSize = "18px";
el.style.display = "none"; // hide
el.style.display = ""; // remove inline style (reverts to CSS)
// Reading computed styles (includes CSS file styles)
const styles = window.getComputedStyle(el);
styles.backgroundColor; // actual computed value
styles.fontSize;Creating and Removing Elements
JavaScript
// Create element
const div = document.createElement("div");
div.className = "card";
div.textContent = "New card";
// Create with innerHTML (faster for complex HTML)
const template = document.createElement("div");
template.innerHTML = `
<article class="card">
<h2>Title</h2>
<p>Description</p>
</article>
`;
const card = template.firstElementChild;
// Append to DOM
document.body.appendChild(div); // add as last child
document.body.prepend(div); // add as first child
parent.insertBefore(div, referenceNode); // insert before specific child
// Modern insert methods
parent.append(div, "text node"); // add multiple, accepts text
parent.before(div); // insert before parent
parent.after(div); // insert after parent
refNode.replaceWith(div); // replace reference node
// Remove
el.remove(); // modern, remove self
parent.removeChild(el); // old way
// Clone
const clone = el.cloneNode(true); // true = deep clone (includes children)Event Listeners
JavaScript
const btn = document.querySelector("#submit-btn");
// Add listener
btn.addEventListener("click", function(event) {
console.log("clicked!", event);
});
// Arrow function (modern)
btn.addEventListener("click", (e) => {
e.preventDefault(); // stop default behavior (form submit, link navigate)
console.log("x:", e.clientX, "y:", e.clientY);
});
// Remove listener — must pass the same function reference
function handleClick(e) { console.log("clicked"); }
btn.addEventListener("click", handleClick);
btn.removeEventListener("click", handleClick);
// Listen once (auto-removes after first trigger)
btn.addEventListener("click", handleClick, { once: true });Common Events
JavaScript
// Mouse events
el.addEventListener("click", handler);
el.addEventListener("dblclick", handler);
el.addEventListener("mouseenter", handler); // no bubbling
el.addEventListener("mouseleave", handler); // no bubbling
el.addEventListener("mouseover", handler); // bubbles
el.addEventListener("mouseout", handler); // bubbles
el.addEventListener("contextmenu", handler); // right click
// Keyboard events
document.addEventListener("keydown", (e) => {
console.log(e.key, e.code, e.ctrlKey, e.shiftKey);
if (e.key === "Enter") { /* submit */ }
if (e.key === "Escape") { /* close modal */ }
if (e.ctrlKey && e.key === "s") {
e.preventDefault();
saveDocument();
}
});
// Form events
form.addEventListener("submit", (e) => {
e.preventDefault(); // always prevent default on forms
const data = new FormData(form);
data.get("username");
});
input.addEventListener("input", (e) => {
// fires on every keystroke
console.log(e.target.value);
});
input.addEventListener("change", (e) => {
// fires when focus leaves after value changed
validateInput(e.target.value);
});
// Window/document events
window.addEventListener("load", () => { /* page fully loaded */ });
document.addEventListener("DOMContentLoaded", () => { /* DOM ready */ });
window.addEventListener("resize", () => { console.log(window.innerWidth); });
window.addEventListener("scroll", () => { console.log(window.scrollY); });Event Delegation
Instead of adding listeners to every item (expensive, doesn't work for dynamic items), add ONE listener to the parent.
JavaScript
// Without delegation — breaks for dynamically added items
document.querySelectorAll(".delete-btn").forEach(btn => {
btn.addEventListener("click", deleteItem); // won't work for future items
});
// With delegation — one listener handles all current AND future items
document.querySelector(".item-list").addEventListener("click", (e) => {
const deleteBtn = e.target.closest(".delete-btn");
if (!deleteBtn) return; // click was elsewhere in the list
const itemId = deleteBtn.dataset.id;
deleteItem(itemId);
});Practical Example: Todo List
JavaScript
const form = document.querySelector("#todo-form");
const input = document.querySelector("#todo-input");
const list = document.querySelector("#todo-list");
let todos = [];
form.addEventListener("submit", (e) => {
e.preventDefault();
const text = input.value.trim();
if (!text) return;
const todo = { id: Date.now(), text, done: false };
todos.push(todo);
input.value = "";
renderTodos();
});
// Event delegation for complete and delete
list.addEventListener("click", (e) => {
const id = Number(e.target.closest("li")?.dataset.id);
if (!id) return;
if (e.target.classList.contains("complete-btn")) {
todos = todos.map(t => t.id === id ? { ...t, done: !t.done } : t);
}
if (e.target.classList.contains("delete-btn")) {
todos = todos.filter(t => t.id !== id);
}
renderTodos();
});
function renderTodos() {
list.innerHTML = todos.map(todo => `
<li data-id="${todo.id}" class="${todo.done ? "done" : ""}">
<span>${todo.text}</span>
<button class="complete-btn">${todo.done ? "Undo" : "Done"}</button>
<button class="delete-btn">Delete</button>
</li>
`).join("");
}Key Takeaways
querySelector/querySelectorAll— the modern way to select elementstextContentfor setting text (safe),innerHTMLfor HTML (watch XSS)classList.add/remove/toggle— cleaner than manipulatingclassNameaddEventListener— always use this, notonclickattributes- Event delegation — one parent listener beats many child listeners
e.preventDefault()— stops form submit, link navigation, right-click menu