2.3 JavaScript: Making It Interactive

Your pages have real structure (HTML) and now look like an actual site (CSS) — but they still just sit there. JavaScript is the language that makes a page respond: click a button and something happens, without you ever reloading the page. This week you're connecting a script file to your site and using it to make your About Me page genuinely interactive. Work through the tasks below in order — each one builds on the last.

Before You Start

  1. Open your 2_web_development folder in VS Code — the same one from the last two weeks, in your H: drive. No new download this week; you're building on what you already made.
  2. Check that it still has index.html, about.html, work.html, and a /js folder with a file called script.js inside it. If script.js is missing, create it now: right-click the js folder → New File → name it exactly script.js.
  3. Open script.js and leave it open in a tab alongside your HTML files — you'll be jumping between them all week.

VS Code reminders

  • Auto Save should still be on — check File > Auto Save has a checkmark.
  • Keep Live Preview open, and keep the browser's Console open too (right-click the page → Inspect → Console tab) — that's where you'll see whether your JavaScript is actually running.
  • JavaScript is picky about spelling and capitalization — an id in your HTML has to match the one in your JavaScript exactly, or nothing will happen.
Monday: your teacher will model Tasks 1 and 2 live, line by line, with everyone typing along — connecting script.js and proving it's running before anyone tries to build anything with it. That walkthrough is Tasks 1–2. Once it's done, you keep going independently through Tasks 3 and 4.

How JavaScript Connects to Your Page (quick reference)

Everything you do this week follows the same three-step pattern:

  1. Select something on the page — find an element using its id.
  2. Listen for something to happen — usually a click.
  3. React — change something about the page when that click happens.
const thing = document.querySelector("#thing-id");

thing.addEventListener("click", function () {
  // what happens when it's clicked
});

You'll use this exact select → listen → react shape in Tasks 2 through 4 — only the details change.

Green

Task 1 — Connect JavaScript and prove it's working

A JavaScript file that isn't linked to your page does absolutely nothing — the exact same trap as an unlinked stylesheet in 2.2. Before you build anything, you need to see proof that your script is actually running.

  1. Add this line just before the closing </body> tag — on all three pages (index.html, about.html, work.html):
    <script src="js/script.js"></script>
  2. In script.js, add:
    console.log("script.js is connected!");
  3. Save everything, then open any of your three pages, right-click → Inspect → Console tab.
Common mistake: the <script> tag goes right before </body>, not up in <head> like your stylesheet link. If it's in <head>, your script tries to run before the rest of the page exists, and Task 2 will break in a confusing way.
🟢 Green: the Console tab shows script.js is connected! on all three pages.
🔴 Red: nothing shows, or you see a red error — check the file path first (js/script.js must match your actual folder), then check for typos.
Green

Task 2 — Select an element and prove you can grab it

Before JavaScript can change anything on your page, it has to be able to find it first. document.querySelector is how your script reaches into your HTML and grabs a specific element.

  1. On about.html, give one element an id — your bio heading works well:
    <h1 id="bio-heading">About Me</h1>
  2. In script.js, select it and log it to prove the connection:
    const bioHeading = document.querySelector("#bio-heading");
    console.log(bioHeading);
  3. Save, then check the Console again.
Customize this: pick a real element from your own about.html — it doesn't have to be the bio heading, just something you'll want to reference again in Task 3.
🟢 Green: the Console shows your actual <h2> element — not null.
🔴 Red: Console shows null — this almost always means either the id doesn't match exactly (check spelling and capitalization) or your <script> tag isn't right before </body>.
Green

Task 3 — Add a click event that changes the page

This is the actual "interactive" part of the week — your page responds to the person using it, instead of just sitting there.

Worked example — a button that reveals a hidden fact

<button id="fact-btn">Show a fun fact about me</button>
<p id="fun-fact" style="display: none;">I once built a robot out of LEGO that could actually walk.</p>
const factBtn = document.querySelector("#fact-btn");
const funFact = document.querySelector("#fun-fact");

factBtn.addEventListener("click", function () {
  funFact.style.display = "block";
});

Your turn — same pattern, your own content

Fill in the blanks using your own idea — a favourite games list, your avatar's backstory, a hidden skills list — the pattern is identical:

<button id="___-btn">___</button>
<p id="___" style="display: none;">___</p>
const ___Btn = document.querySelector("#___");
const ___ = document.querySelector("#___");

___.addEventListener("click", function () {
  ___.style.display = "block";
});
Customize this: the fun fact is just one option — a "reveal my top 3 games," a "click to see my avatar's backstory," or a hidden skills list all work the same way. Content is yours; the click → reveal pattern is what's assessed.
🟢 Green: clicking your button makes something real appear on the page — not just a console log.
🔴 Red: nothing happens on click — check that the ids in your JavaScript exactly match the ids in your HTML. This is the #1 bug this week.
Green

Task 4 — Apply the pattern to several things at once

Task 3 changed one thing when you clicked one button. Real interactivity usually means the same behaviour applied across a group of elements — this is the step from "a button" to "a pattern." Turn a list on your page (skills, interests, favourite games) into individually-expandable items: clicking any one of several elements reveals more detail about that one, using a loop instead of writing the same code five times.

Starter code

<ul class="skills-list">
  <li class="skill-pill">HTML <span class="skill-detail" style="display: none;">Building semantic page structure since Unit 2, Week 1.</span></li>
  <li class="skill-pill">CSS <span class="skill-detail" style="display: none;">Learned flexbox nav and box-model spacing.</span></li>
  <li class="skill-pill">Problem solving <span class="skill-detail" style="display: none;">Debugged my own null-selector bug in Task 2!</span></li>
</ul>
const skillPills = document.querySelectorAll(".skill-pill");

skillPills.forEach(function (pill) {
  pill.addEventListener("click", function () {
    const detail = pill.querySelector(".skill-detail");
    detail.style.display = "inline";
  });
});
Reference — what's different here: querySelectorAll grabs every matching element as a list, not just one. .forEach then runs the same code once for each item in that list — so instead of writing the click logic three separate times, you write it once and it applies to all of them.
Customize this: use your own list — three interests, three favourite games, three skills — with your own detail text for each. Keep the class names skill-pill and skill-detail, or rename them consistently in both your HTML and your JavaScript.
🟢 Green: clicking any pill reveals its own detail — not all of them at once, and not just the first one.
🔴 Red: clicking one pill reveals all of them, or only the first one ever works — this usually means querySelector was used instead of querySelectorAll + .forEach, so double-check that.
Black menu

Pick one or two, not all eight

This is where you make the site genuinely yours — pick whichever sound the most fun.

Dark mode toggle that remembers your choice

You may have already built a CSS-only dark mode switch in 2.2. This version goes further: use JavaScript's localStorage to remember the person's choice, so it's still dark mode the next time they open your site.

Typewriter effect

Your homepage tagline types itself out letter by letter instead of just appearing all at once.

Random fun-fact generator

A button that shows a different random fact from a list each time you click it, using Math.random().

Image lightbox

Clicking a thumbnail on your Work page opens it bigger in an overlay.

Mini self-quiz

A 2–3 question quiz about you ("guess my favourite game") with right/wrong feedback when someone answers.

Scroll reveal

Sections fade in as you scroll down the page instead of all being visible at once. (Stretch — uses IntersectionObserver.)

Contact form with validation

A form that checks the fields aren't empty and gives feedback — without actually sending anything anywhere.

Console easter egg

A styled message in the browser console for anyone curious enough to open DevTools.

Checkpoint for any Black task: does it actually work when someone else clicks or tries it — not just when you do (since you already know where the bugs are)?