Ch. 11 — JavaScript DOM
Chapter 11 Phase 2 — UX Engineer

JavaScript That Actually Does Things

HTML and CSS describe what things look like. JavaScript makes them behave.

⏱ 1.5 hours 🛠 VS Code · Browser

The line between Phase 1 and Phase 2

Everything you learned in Phase 1 — HTML structure, CSS styling, design tokens, components — was about the appearance of things. You can build beautiful static pages. But they don't respond yet. A button that can't be clicked is furniture.

JavaScript is the thing that makes your designs come alive. A dropdown that opens. A form that validates. A counter that increments. A list that adds and removes items without refreshing the page. This is what separates a mockup from a product.

💡 You already know more than you think
JavaScript is just instructions
Programming feels intimidating because it looks like math. It isn't. It's just telling a computer what to do, step by step, in a very precise way. You already think this way when you write a recipe or create a Figma prototype flow.

Variables — giving things names

A variable is a label you attach to a piece of data so you can refer to it later. That's it.

javascript
// const = a value that won't change
const userName = "Alex";
const userAge = 28;

// let = a value that might change
let isLoggedIn = false;
let cartCount = 0;

// Using your variables
console.log("Hello, " + userName);
isLoggedIn = true; // now they're logged in
cartCount = cartCount + 1; // added something to cart
🔤 Jargon decoded
const vs let
Use const when the value won't change (a user's name, a DOM element you looked up). Use let when it will (a counter, a boolean toggle). Avoid var — it's the old way and has quirky behavior.

Functions — reusable blocks of logic

A function is a named set of instructions you can run whenever you need them. Instead of writing the same code ten times, you write it once and call it by name.

javascript
// Define a function
function greetUser(name) {
  return "Welcome back, " + name + "!";
}

// Call it
const message = greetUser("Alex"); // "Welcome back, Alex!"
const message2 = greetUser("Sam"); // "Welcome back, Sam!"

// Arrow function — same thing, shorter syntax
const greet = (name) => "Welcome back, " + name + "!";
const msg = greet("Jordan"); // "Welcome back, Jordan!"

The DOM — JavaScript's map of your HTML

The DOM (Document Object Model) is how JavaScript sees your HTML. When a page loads, the browser reads your HTML and creates a tree of objects — every element becomes a JavaScript object you can grab, change, add to, or remove.

javascript
// Find elements
const title = document.querySelector('h1');
const button = document.querySelector('.submit-btn');
const allCards = document.querySelectorAll('.card');

// Read their content
console.log(title.textContent); // "My Page Title"

// Change their content
title.textContent = "New Title";
title.style.color = "#f5e642";

// Add/remove CSS classes (the right way to style with JS)
button.classList.add('btn--loading');
button.classList.remove('btn--default');
button.classList.toggle('btn--active'); // on/off switch

// Create new elements
const newCard = document.createElement('div');
newCard.className = 'card';
newCard.textContent = 'New card content';
document.querySelector('.card-grid').appendChild(newCard);
💡 Designer's rule
Never set styles directly in JavaScript if you can help it
Use classList.add/remove/toggle to apply CSS classes from your stylesheet instead of element.style.color = '...'. Your CSS stays in CSS, your JavaScript stays in JavaScript. This is cleaner, more maintainable, and easier to debug.

Events — making things respond

An event is something that happens: a click, a keystroke, a form submission, the page loading, the mouse moving. JavaScript "listens" for these events and runs code when they occur.

javascript
const btn = document.querySelector('#myButton');

// Listen for a click
btn.addEventListener('click', function() {
  console.log('Button was clicked!');
  btn.textContent = 'Clicked!';
  btn.classList.add('btn--active');
});

// Listen for form input
const input = document.querySelector('#searchInput');
input.addEventListener('input', function(event) {
  const searchTerm = event.target.value;
  console.log('User typed:', searchTerm);
});

// Listen for keyboard events
document.addEventListener('keydown', function(event) {
  if (event.key === 'Escape') {
    closeModal();
  }
});
  • click — user clicks on an element
  • input — user types in an input field
  • submit — user submits a form
  • keydown / keyup — user presses or releases a key
  • mouseover / mouseout — cursor enters or leaves an element
  • DOMContentLoaded — page has loaded and DOM is ready

Putting it together: a real interactive pattern

Here's the full pattern you'll use over and over: listen for an event, read some data, update the DOM. This is how virtually every UI interaction works, regardless of framework.

javascript
// A simple to-do list — the "Hello World" of interactivity
const input = document.querySelector('#taskInput');
const addBtn = document.querySelector('#addBtn');
const list = document.querySelector('#taskList');

addBtn.addEventListener('click', function() {
  const taskText = input.value.trim();
  if (!taskText) return; // don't add empty items

  // Create a new list item
  const item = document.createElement('li');
  item.textContent = taskText;

  // Add a delete button to it
  const del = document.createElement('button');
  del.textContent = '×';
  del.addEventListener('click', function() {
    item.remove();
  });
  item.appendChild(del);

  // Add it to the list
  list.appendChild(item);
  input.value = ''; // clear the input
  input.focus();    // put cursor back in input
});
💚 Pattern recognition
This same pattern runs the entire web
A shopping cart adding items. A filter hiding products. A sidebar opening. A modal appearing. Every single one of these is: listen for event → read data → update DOM. The frameworks (React, Vue) automate this pattern, but the underlying logic is identical.
⚠ Error anatomy
What JavaScript errors actually look like
Open DevTools (Cmd + Option + I) and click the Console tab. When something breaks:

Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
querySelector() found nothing. The selector is wrong or the element does not exist yet.

Uncaught ReferenceError: addBtn is not defined
→ Variable used before it was declared. Check for a typo in the variable name.

undefined logged in the console
→ A variable exists but has no value, or you are reading a property that does not exist on an object.
Hands-on activity
Build an interactive to-do list
You need: The in-page IDE below
  1. 1
    Look at the starter code in the IDE below. It already has the HTML structure (an input, a button, and an empty list). Your job is to write the JavaScript that makes it work.
  2. 2
    Find the <script> tag at the bottom of the HTML. Write code to: grab the input, button, and list elements using querySelector. Add a click listener to the button. On click: read the input value, create a new <li>, add it to the list.
  3. 3
    Add a delete button to each item. When clicked, remove that <li> from the DOM using .remove().
  4. 4
    Bonus: Add keyboard support — pressing Enter in the input should also add the item (listen for the keydown event and check if event.key === 'Enter').
Try it right here
Build a to-do list with vanilla JavaScript
💥
Break-it challenge
This to-do list is broken. Fix it using the console.
You need: The IDE below Chrome DevTools (Cmd + Option + I)
  1. 1
    Click ▶ Run. Try clicking Add. Nothing happens. There is a bug in the JavaScript.
  2. 2
    Open DevTools (Cmd + Option + I) → Console tab. Read the error. It tells you the error type and the line number.
  3. 3
    Find the mismatch between the JavaScript selector and the HTML. Fix it and re-run until the list works.
Break-it challenge
Find the bug using the console
✦ Own your code
Can you explain every line?
Before moving on: pick any 5 lines from the code above and say out loud what each one does. Not the general idea — the specific line. If Claude ever gives you code like this, hold it to this standard before you use it. If you cannot explain a line, you cannot debug it.
Key takeaways
  • const for values that don't change, let for values that do
  • document.querySelector('.selector') finds the first matching element; querySelectorAll finds all of them
  • Change content with .textContent; change styles by toggling CSS classes with .classList.add/remove/toggle
  • addEventListener('click', fn) is the foundation of all interactivity
  • The core pattern: listen for event → read data → update DOM. Frameworks automate this, but they all do the same thing underneath