Day 27 - DOM Manipulation & Events

Day 27: DOM Manipulation & Events

Making Web Pages Interactive ๐ŸŽฎ

Today we unlock JavaScript's superpower: dynamically changing web pages!

Today's Journey:

  • ๐ŸŒณ Understanding the DOM tree structure
  • ๐ŸŽฏ Selecting elements with precision
  • โœจ Creating and modifying elements
  • ๐ŸŽช Handling user events
  • ๐ŸŽจ Project: Etch-a-Sketch (if time permits)

What is the DOM? ๐ŸŒณ

Document Object Model

The DOM is: A tree-like representation of your HTML that JavaScript can interact with

<div id="container">
  <div class="display"></div>
  <div class="controls"></div>
</div>

๐Ÿ“ฆ Nodes

Everything in the DOM (elements, text, comments)

๐Ÿท๏ธ Elements

HTML tags that become element nodes

๐ŸŒ Web History Moment ๐Ÿ“œ

The Web's First Browser Had Editing Built In

Tim Berners-Lee's Vision (1990)

  • The original web browser ran on NeXT computers and showed Tim Berners-Lee's revolutionary vision
  • It had many features of current web browsers - but with one amazing difference
  • Built-in editing capability! You could modify web pages directly from inside the browser
  • This was the first web editing functionality - decades before modern developer tools
Source: CERN - "A short history of the Web"
๐Ÿ’ก Connection to Today: DOM manipulation fulfills Tim Berners-Lee's original vision of an interactive, editable web. What we're learning today is the foundation that makes the modern web dynamic and user-controlled!
๐Ÿค” Reflection Question: How would the web be different today if editing capabilities had remained a standard browser feature from the beginning?

DOM Family Tree ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ

Understanding Relationships

<div id="container"> <-- Parent
  <div class="display"></div> <-- Child & Sibling
  <div class="controls"></div> <-- Child & Sibling
</div>

Parent-Child

Elements directly inside another

Siblings

Elements at the same level

Ancestors

All parent elements up the tree

Descendants

All child elements down the tree

Targeting Elements ๐ŸŽฏ

Query Selectors

// Select by ID
const container = document.querySelector("#container");

// Select by class
const display = document.querySelector(".display");

// Select by tag
const divs = document.querySelectorAll("div");

// Complex selectors (CSS-style)
const button = document.querySelector("#container > button.primary");
Remember: querySelector returns ONE element, querySelectorAll returns a NodeList (like an array, but not quite!)

Navigating the DOM Tree ๐Ÿงญ

Using Relationships

const container = document.querySelector("#container");

// Navigate to children
const firstChild = container.firstElementChild;
const lastChild = container.lastElementChild;
const allChildren = container.children;

// Navigate to siblings
const nextSibling = element.nextElementSibling;
const prevSibling = element.previousElementSibling;

// Navigate to parent
const parent = element.parentElement;
Pro Tip: Use these when you need to move through the DOM based on structure, not selectors!

Creating Elements ๐Ÿ—๏ธ

Building DOM Nodes in Memory

// Step 1: Create element in memory
const newDiv = document.createElement("div");

// Step 2: Add content and attributes
newDiv.textContent = "Hello World!";
newDiv.classList.add("my-class");
newDiv.setAttribute("id", "new-div");

// Step 3: Add to DOM (makes it visible!)
container.appendChild(newDiv);
Important: Elements exist in memory until you append them to the DOM!

Changing Elements โœ๏ธ

Content, Style, and Classes

Modify Text Content

element.textContent = "New text";
element.innerHTML = "<strong>Bold</strong>";

Modify Attributes

element.setAttribute("href", "https://...");
element.id = "new-id";
element.src = "image.jpg";

Modify Styles

element.style.color = "red";
element.style.backgroundColor = "blue";

Modify Classes

element.classList.add("active");
element.classList.remove("hidden");
element.classList.toggle("selected");

๐Ÿ–ผ๏ธ Web History Moment ๐Ÿ“œ

Mosaic Made the Web Accessible

The Browser That Changed Everything (1993)

  • In 1993, the Mosaic web browser was revolutionary - it was the first application to download images and text together
  • It laid everything out in the same document, like a printed magazine page - this seems obvious now, but it was groundbreaking!
  • Mosaic was the spark that popularized the web - making it accessible to everyday users
  • The Mosaic browser quickly spawned Netscape Navigator, from which Mozilla Firefox is descended
Source: "A Short History of the Web โ€“ Full Stack Web Development"
๐Ÿ’ก Connection to Today: DOM manipulation evolved from Mosaic's static document display to dynamic, interactive content. The methods we're learning allow us to change those "magazine pages" in real-time based on user interaction!
๐Ÿค” Reflection Question: How did Mosaic's ability to display images alongside text transform user expectations for the web? What parallels do you see with modern web capabilities?

Removing Elements ๐Ÿ—‘๏ธ

Cleaning Up the DOM

// Modern way - remove itself
element.remove();

// Classic way - parent removes child
parent.removeChild(element);

// Example: Remove all buttons
const buttons = document.querySelectorAll("button");
buttons.forEach(button => button.remove());
Note: Removing an element also removes all its children!

classList Methods ๐ŸŽจ

The Best Way to Style with JS

// Add a class
element.classList.add("active");

// Remove a class
element.classList.remove("hidden");

// Toggle a class (add if missing, remove if present)
element.classList.toggle("dark-mode");

// Check if element has a class
if (element.classList.contains("selected")) {
  console.log("Element is selected!");
}
Best Practice: Use classes for styling, not inline styles!

What are Events? โšก

Listening for User Actions

Events are actions that happen in the browser:

click

User clicks an element

mouseenter

Mouse moves over an element

keydown

User presses a key

input

User types in an input field

And many more! focus, blur, submit, scroll, etc.

addEventListener() ๐Ÿ‘‚

The Modern Way

// Basic syntax
element.addEventListener(eventType, callback);

// Example: Click handler
const button = document.querySelector("#myButton");

button.addEventListener("click", function() {
  alert("Button clicked!");
});

// Arrow function version
button.addEventListener("click", () => {
  console.log("Clicked!");
});

Common Event Types ๐ŸŽช

What Can You Listen For?

Mouse Events

  • click
  • dblclick
  • mouseenter
  • mouseleave
  • mousedown
  • mouseup
  • mousemove

Keyboard Events

  • keydown
  • keyup
  • keypress

Form Events

  • input
  • change
  • submit
  • focus
  • blur

Callback Functions ๐Ÿ“ž

Functions as Arguments

// Anonymous function (inline)
button.addEventListener("click", function() {
  console.log("Clicked!");
});

// Arrow function
button.addEventListener("click", () => {
  console.log("Clicked!");
});

// Named function (reusable!)
function handleClick() {
  console.log("Button was clicked!");
}
button.addEventListener("click", handleClick);

// With event object
button.addEventListener("click", (e) => {
  console.log(e.target); // The clicked element
  e.target.style.background = "blue";
});

The Event Object ๐Ÿ“ฆ

Information About What Happened

button.addEventListener("click", function(e) {
  // e is the event object
  console.log(e.type); // "click"
  console.log(e.target); // Element that was clicked
  console.log(e.currentTarget); // Element with listener
  console.log(e.clientX); // Mouse X position
  console.log(e.clientY); // Mouse Y position
  console.log(e.timeStamp); // When it happened
});

// Prevent default behavior
link.addEventListener("click", (e) => {
  e.preventDefault(); // Stop link navigation
});

Events on Multiple Elements ๐ŸŽญ

Using forEach with NodeLists

// Select ALL buttons
const buttons = document.querySelectorAll("button");

// Add listener to EACH button
buttons.forEach((button) => {
  button.addEventListener("click", () => {
    alert(`You clicked ${button.textContent}`);
    button.classList.toggle("clicked");
  });
});

// Or use the event target to identify which one
buttons.forEach((button) => {
  button.addEventListener("click", (e) => {
    console.log(`Clicked: ${e.target.textContent}`);
  });
});

Event Bubbling ๐Ÿซง

Events Travel Up the Tree

When an event happens on an element, it "bubbles up" to its parents!

<div id="parent">
  <button id="child">Click me</button>
</div>

// Click on button triggers BOTH listeners!
parent.addEventListener("click", () => {
  console.log("Parent clicked");
});

child.addEventListener("click", (e) => {
  console.log("Child clicked");
  e.stopPropagation(); // Stops bubbling
});

Common DOM Patterns ๐Ÿ“š

Real-World Examples

Toggle Dark Mode

btn.addEventListener("click", () => {
  document.body.classList.toggle("dark");
});

Form Validation

input.addEventListener("blur", (e) => {
  if (!e.target.value) {
    e.target.classList.add("error");
  }
});

Dynamic List

addBtn.addEventListener("click", () => {
  const li = document.createElement("li");
  li.textContent = input.value;
  list.appendChild(li);
});

Remove on Click

item.addEventListener("click", (e) => {
  e.target.remove();
});

โšก Web History Moment ๐Ÿ“œ

JavaScript Gave the Web Interactivity

The Dawn of Dynamic Web Pages (1995)

  • In 1995, Netscape Navigator began to support dynamic content on web pages through JavaScript and Java Applets
  • Before this, web pages were completely static - you could only read them, not interact with them
  • Duke, the Java mascot, changed everything! A popular animation showed Duke slowly tumbling across web pages
  • This simple animation blew everyone away - it proved that web pages could be alive and interactive!
Source: "A Short History of the Web โ€“ Full Stack Web Development"
๐Ÿ’ก Connection to Today: DOM manipulation is the foundation of ALL web interactivity today. Every animation, every button click, every dynamic update you see on modern websites - it all traces back to these pioneering experiments in 1995. You're learning the technology that powers the interactive web!
๐Ÿค” Reflection Question: Imagine showing a 1995 web developer a modern interactive web application (like Google Maps or Netflix). What do you think would surprise them most about how far DOM manipulation has evolved?

Where to Put Your Script? ๐Ÿ“

Timing is Everything!

โŒ Problem: Script in Head

<head>
  <script src="script.js"></script>
</head>

DOM doesn't exist yet!

โœ… Solution 1: Script at Bottom

<body>
  ...
  <script src="script.js"></script>
</body>

DOM loads first!

โœ… Solution 2: defer Attribute

<head>
  <script src="script.js" defer></script>
</head>

Waits for DOM!

Project: Etch-a-Sketch ๐ŸŽจ

Let's Build Something!

Project Goals:

  • Create a grid of squares using JavaScript
  • Change square colors on hover
  • Add a button to reset the grid
  • Allow users to choose grid size
  • Bonus: Add color options!

Skills You'll Practice:

createElement, appendChild, addEventListener, loops, classList, querySelector

Step 1: Create the Grid ๐Ÿ—‚๏ธ

Nested Loops for Structure

// Create a 16x16 grid
const container = document.querySelector("#container");

function createGrid(size) {
  for (let i = 0; i < size * size; i++) {
    const square = document.createElement("div");
    square.classList.add("grid-square");
    container.appendChild(square);
  }
}

createGrid(16); // 256 squares!
CSS Tip: Use display: grid; or flexbox to arrange squares!

Step 2: Add Hover Effect ๐Ÿ–ฑ๏ธ

mouseenter Event

// Get all squares
const squares = document.querySelectorAll(".grid-square");

// Add hover effect to each
squares.forEach((square) => {
  square.addEventListener("mouseenter", () => {
    square.style.backgroundColor = "black";
    // Or add a class:
    // square.classList.add("colored");
  });
});
Remember: Add event listeners AFTER creating elements!

Step 3: Reset Button ๐Ÿ”„

Clear and Rebuild

const resetBtn = document.querySelector("#reset");

resetBtn.addEventListener("click", () => {
  // Option 1: Clear all styles
  squares.forEach(square => {
    square.style.backgroundColor = "white";
  });

  // Option 2: Rebuild grid
  container.innerHTML = ""; // Clear all
  createGrid(16); // Rebuild
});

Step 4: Custom Grid Size ๐Ÿ“

User Input with prompt()

const sizeBtn = document.querySelector("#change-size");

sizeBtn.addEventListener("click", () => {
  let size = prompt("Enter grid size (max 100):");
  size = parseInt(size);

  // Validate input
  if (size > 0 && size <= 100) {
    container.innerHTML = "";
    createGrid(size);
  } else {
    alert("Please enter a number between 1 and 100");
  }
});

Bonus Challenges ๐Ÿ†

Level Up Your Project!

๐ŸŒˆ Random Colors

const randomColor = () => {
  const r = Math.floor(Math.random() * 256);
  const g = Math.floor(Math.random() * 256);
  const b = Math.floor(Math.random() * 256);
  return `rgb(${r}, ${g}, ${b})`;
};

๐ŸŒ‘ Progressive Darkening

Each pass makes square 10% darker

Use opacity or RGB calculations

๐ŸŽจ Color Picker

Let user choose the drawing color

๐Ÿงน Clear Button

Reset all squares to white

CSS Grid Layout ๐ŸŽฏ

Making Squares Arrange Properly

/* Container */
#container {
  display: grid;
  grid-template-columns: repeat(16, 1fr);
  width: 500px;
  height: 500px;
  border: 2px solid black;
}

/* Each square */
.grid-square {
  border: 1px solid #ddd;
  aspect-ratio: 1;
}

/* Important! */
* {
  box-sizing: border-box;
}
Pro Tip: Use box-sizing: border-box;

You Now Know DOM Manipulation! ๐ŸŽ“

Today's Superpowers:

  • โœ… Navigate the DOM tree structure
  • โœ… Select elements with querySelector
  • โœ… Create new elements dynamically
  • โœ… Modify element properties and styles
  • โœ… Add interactive event listeners
  • โœ… Handle multiple elements efficiently
  • โœ… Understand event bubbling
  • โœ… Appreciate the history of web interactivity!

Practice Resources:

  • ๐Ÿ“– MDN DOM Documentation
  • ๐ŸŽฎ JavaScript30 by Wes Bos
  • ๐Ÿ’ช Complete the Etch-a-Sketch project
  • ๐ŸŒ Explore early web browser histories