How JavaScript
controls a webpage
A complete visual tour of every HTML tag, JavaScript function, array, and method used to build the shopping cart, with interactive labs you can click through.
Use ← → arrow keys or the buttons below to navigate
Every interaction follows the same four steps
HTML gives the page structure. JavaScript finds parts of it, waits for a person to act, then changes the data and the page.
HTML landmarks
Tags with id, class, and data-id labels.
Like street signs on a map
Find elements
getElementById, querySelector, querySelectorAll.
Like looking up an address
Listen for events
addEventListener("click", …) waits for the person to act.
Like a lookout on watch
Update data and page
Change the cart array, then redraw with updateCart().
Like updating a scoreboard
Where each idea shows up in the program
div, h2, p, img, button, class#cart-items, #cart-totalproducts array, getElementById, forEach, innerHTMLaddEventListener, dataset.id, find, push++, totals, toFixed(2), updateCart()findIndex, splice, listeners on new buttonsThree files, three jobs
The project folder holds three files. The HTML file connects the other two.
index.html
The structure: what is on the page.
styles.css
The style: colors, spacing, layout.
script.js
The behavior: what happens when you interact.
index.html: the browser reads top to bottom
<!DOCTYPE html>
<html>
<head>
<title>Tech Shop</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="product-list" class="product-grid"></div>
<h2 class="section-title">Your Cart</h2>
<p id="empty-cart-message">Your cart is empty.</p>
<div id="cart-items" class="cart-items"></div>
<div id="cart-total"></div>
<script src="script.js"></script>
</body>
</html>Why it is ordered this way
<link>Goes in <head> so styles load before anything appears.<script>Goes just before </body>. The browser reads top to bottom, so every element already exists when JavaScript looks for it.empty ids#product-list and #cart-items start empty. They are placeholders JavaScript fills in later.⚠ order bugIf <script> runs in <head>, getElementById("cart-items") returns null because the cart list has not been read yet.Every HTML tag in the project
Click a tag to see what it does and where it appears on the page.
Attributes are labels JavaScript can read
Attributes go inside the opening tag as name="value". Hover a row to find it in the code.
One product card + the cart list
idclassdata-idsrcalthref / rel<link> to connect styles.css.<link rel="stylesheet" href="styles.css">The DOM is the page as a family tree
The browser turns your HTML into a tree of objects called the Document Object Model. JavaScript starts at document and works its way down to find any element.
Every element object has properties you can read and change
.textContentThe plain text inside.innerHTMLThe HTML inside, as a string.classNameThe class attribute, as text.classList.add()Add one class without removing others.dataset.idReads the data-id attribute.style.displayShow ("block") or hide ("none").appendChild()Add a child element inside this one.addEventListener()React when something happens to itThree ways to find elements
Before JavaScript can change something, it has to find it. Each method asks the document a different kind of question.
getElementById
const cartItems =
document.getElementById("cart-items");
null if no match.⚠ No
#, just the id name.querySelector
document.querySelector("p"); // tag
document.querySelector(".my-div"); // class
document.querySelector("#myDiv"); // id
null.querySelectorAll
const buttons = document
.querySelectorAll(".add-to-cart-button");
buttons.forEach((button) => { ... });
forEach.Selector cheat sheet
| Write | Means | Matches in our project |
|---|---|---|
| #name | element with id="name" | #cart-items → the cart <div> |
| .name | elements with class="name" | .product-card → every card |
| tag | elements of that tag | button → every button |
| a b | b somewhere inside a | #cart-items .cart-item → rows in the cart |
| [attr] | by attribute value | [data-id="candy"] → the candy button |
🔬 Selector playground
Choose a method, then a selector, or type your own. Matching elements light up on the real page below, numbered in the order JavaScript finds them.
Your Cart
Your cart is empty.
Variables, operators, and decisions
A variable is a labeled box for a value. const means the label always points to the same box; let means you can swap in a new value later.
"Minecraft"29.99true, false{ }, [ ]Arithmetic
| = | assign: let total = 0 |
| + - | add / subtract |
| * / | multiply / divide: price * quantity |
| += | add to itself: total += itemTotal |
| ++ | add 1: quantity++ |
| -- | subtract 1: quantity-- |
Comparison (gives true / false)
| === | equal value and type ✅ use this |
| == | equal value, loose (avoid) |
| !== | not equal |
| > < | greater / less than |
| >= <= | or equal to |
"1" === 1 is false: a string is not a number.
Try it: if / else in removeFromCart
cart[index].quantity =
cart[index].quantity--; // take one away
cart.splice(index, 1); // remove the row
}
Objects describe one thing
An object groups related values as key: value pairs. Each product is an object, and each cart item is a product object plus a quantity.
Lab: read, change, and add fields
Why these matter in the cart
// One product object (Week 4)
const product = {
id: "candy",
name: "Sour Patch Kids",
price: 1.29,
image: "candy.jpg",
};
product.name; // read → "Sour Patch Kids"
product.price = 2.00; // change a field
product.category = "Snack"; // add a new field
// Spread ... copies every field into a NEW object,
// then adds quantity (Week 5, addToCart)
cart.push({ ...product, quantity: 1 });
💡 The ... spread makes a copy, so changing the cart item's quantity doesn't change the original product.
Arrays are ordered lists
The project uses two arrays: products (everything for sale) and cart (what the shopper picked). Positions are counted from 0.
products: the store shelf (never changes)
const products = [
{ id: "game", name: "Minecraft", price: 29.99 },
{ id: "candy", name: "Sour Patch Kids", price: 1.29 },
];
products[0].name; // "Minecraft"
products.length; // 2
cart: the shopping basket (changes on every click)
const cart = []; // starts empty
// after clicking Minecraft twice and candy once:
[
{ id: "game", name: "Minecraft", price: 29.99, quantity: 2 },
{ id: "candy", name: "Sour Patch Kids", price: 1.29, quantity: 1 },
]
push() adds to the end
pop() removes the last item · splice() removes from anywhere
find() returns the item · findIndex() returns its position
forEach() runs code once for every item
🔬 Array method lab
Run each method and watch the array change. Output is shown in the console below, just like console.log.
Functions are reusable recipes
A function is a named set of steps. You define it once, then call it whenever you need it. Hover each part:
const product = products.find(...);
...
}
addToCart("game"); // call it
Arrow functions: the short form
// These two do the same thing:
function (p) { return p.id === productId; }
(p) => p.id === productId
You see arrow functions inside forEach, find, and addEventListener. They're small functions handed to another function.
The 5 functions of the shopping cart
products and puts a card on the page for each one. · Week 4Who calls whom?
The functions call each other in a chain. Press a trigger to watch the chain run.
Key rule
Every time the cart array changes, call updateCart() so the page matches the data. The data is the source of truth; the page is a picture of it.
🔬 Building new elements, step by step
createElement makes an element in memory. It is not on the page until appendChild places it there.
Template literals build HTML with values
const name = "Minecraft";
const price = 29.99;
// Backticks ` ` let you insert values with ${ }
card.innerHTML = `
<h2>${name}</h2>
<p>$${price.toFixed(2)}</p>
`;
// toFixed(2) → "29.99" (always 2 decimals)Try it: innerHTML vs textContent
innerHTML reads tags as HTML. textContent shows them as plain text. Use textContent for plain words.
Event listeners make the page respond
An event is something that happens: a click, the mouse moving over an element, or a key press. A listener is the function that runs when its event happens.
addToCart(button.dataset.id);
});
The element to watch, found with
querySelectorAllThe event name:
"click", "mouseover", "keydown"The function to run. It waits and does not run until the event happens.
Try three event types
⚠ Elements created later need their listener when they're created
Remove buttons don't exist when the page loads, so querySelectorAll at the start can't find them. Attach the listener right after creating each one inside updateCart():
const removeButton = document.createElement("button");
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => removeFromCart(item.id));
🔬 Watch the whole script.js run, line by line
Your Cart
Your cart is empty.
Common bugs and how to fix them
Open DevTools (right-click → Inspect → Console) and add console.log(something) to see what's really in a variable.
getElementById doesn't match the HTML, or it includes a #.displayProducts is defined but never called.displayProducts();cart array was updated but the page was never redrawn.updateCart() after every changeupdateCart adds rows without clearing the old ones.innerHTML = ""class name has a typo.displayProducts()find returns undefineddataset.id is always a string. "1" === 1 is false.id: "1".toFixed(2)addEventListener inside updateCartEvery tag, function, and method in one table
The pattern behind every interaction
Discussion: what does JavaScript need to know to update the correct part of the page?