Session 17 — Build a Real App
Duration: 75 min · Format: live online · Ages: 12–15
Session goal: by the end, students have built a complete, working quiz app in CodePen — questions, answer buttons, score tracking, and a final result — combining all three layers.
Before class — prep (5 min)
- Open CodePen → Create → Pen, signed into a free account so you (and students) can save. You'll build the full quiz live across all three panels.
- Have the finished quiz Pen ready in a second tab as a reference in case you need to jump ahead.
- Send students the CodePen link. Remind them: this app is what they'll deploy to the real internet in Session 18, so save often.
Agenda
| Time | Segment |
|---|---|
| 0:00 | Hook — what's the smallest "real app"? (5 min) |
| 0:05 | Teach — plan the app and store the questions (13 min) |
| 0:18 | Teach — show a question and react to a click (17 min) |
| 0:35 | Activity — build the quiz end to end (23 min) |
| 0:58 | Check for understanding (10 min) |
| 1:08 | Wrap-up + homework (7 min) |
0:00 · Hook (5 min)
Ask the class and take a few answers (chat or unmute):
- "You've learned structure, style, and behaviour. What's the smallest real app you could build with just those?"
- "Think of a quiz you've taken online — what does it need to remember as you go?" (Which question you're on, and your score.)
Land the idea: an app is just the three layers working together, plus a bit of memory — state — that changes as you use it. Today they build a full quiz: it asks questions, checks answers, keeps score, and shows a result. Same skills as any app you've used.
0:05 · Teach — Plan the app and store the questions (13 min)
Explain first, code second. A good developer plans before typing. Sketch the app out loud: - Show a question and some answer buttons. - When an answer is clicked, check if it's right, update the score, and move to the next question. - At the end, show the final score.
Picture the quiz-app flow: show a question, pick an answer, score it, loop to the next, then show the result.
Explain the data. Instead of writing each question into the HTML by hand, we store them as data — an array (an ordered list) of objects (each a question with its answer). This is the same idea as a dataset from Unit 1.
Type/run this together in CodePen (in the JS panel):
const questions = [
{ text: "What does HTML build?", options: ["Structure", "Coffee"], answer: "Structure" },
{ text: "What does CSS add?", options: ["Style", "Sound"], answer: "Style" },
{ text: "What makes a page interactive?", options: ["JavaScript", "Magic"], answer: "JavaScript" }
];
let current = 0;
let score = 0;
console.log("Total questions:", questions.length);
Point out the shape: questions is an array (square brackets [ ]); each item is an object (curly braces { }) with a text, an options list, and the correct answer. current tracks which question we're on; score counts correct answers. These two variables are the app's state.
⚠ Watch for the #1 confusion: arrays are counted from 0, not 1.
questions[0]is the first question.currentstarts at 0 for exactly this reason.
0:18 · Teach — Show a question and react to a click (17 min)
Explain: we need one function that draws the current question, and a click handler that checks the answer. First the HTML shell and some style:
Type/run this together in CodePen (HTML):
<div id="quiz">
<h1 id="question">Question goes here</h1>
<div id="options"></div>
<p id="score">Score: 0</p>
</div>
#quiz {
max-width: 400px;
margin: 40px auto;
font-family: sans-serif;
text-align: center;
}
button {
display: block;
width: 100%;
margin: 8px 0;
padding: 12px;
border: none;
border-radius: 8px;
background-color: #16233A;
color: white;
font-size: 16px;
cursor: pointer;
}
Now the function that shows a question (JS):
const questionEl = document.getElementById("question");
const optionsEl = document.getElementById("options");
const scoreEl = document.getElementById("score");
function showQuestion() {
const q = questions[current];
questionEl.textContent = q.text;
optionsEl.innerHTML = "";
for (const option of q.options) {
const btn = document.createElement("button");
btn.textContent = option;
btn.addEventListener("click", function () {
checkAnswer(option);
});
optionsEl.appendChild(btn);
}
}
Walk through it slowly: we read the current question, set its text, clear the old buttons, then loop over the options and build a fresh button for each — wiring each one to checkAnswer.
Ask: "Why do we clear optionsEl.innerHTML before adding buttons?" (Answer: otherwise the previous question's buttons pile up on screen.)
0:35 · Activity — Build the quiz end to end (23 min)
Have students work in their own Pen alongside you. Add the two remaining functions, then start the quiz. Screen-share as a model.
Type/run this together in CodePen (JS — add below showQuestion):
function checkAnswer(choice) {
if (choice === questions[current].answer) {
score = score + 1;
}
current = current + 1;
if (current < questions.length) {
scoreEl.textContent = "Score: " + score;
showQuestion();
} else {
showResult();
}
}
function showResult() {
questionEl.textContent = "Done! You scored " + score + " / " + questions.length;
optionsEl.innerHTML = "";
scoreEl.textContent = "";
}
showQuestion();
Run the whole quiz live — click through all three questions to the result screen. Point out the final line: showQuestion() starts everything by drawing the first question.
Then have them make it theirs: change the questions to their own topic (football, music, science), add a fourth question to the array, and restyle the buttons with their colours from Session 15.
Circulate for (or watch the chat for) the two errors nearly everyone hits — forgetting the final showQuestion(); call (so the app loads blank), and comparing with = instead of === inside the if.
Demo the Debug Game. Share this broken check and ask students to spot two mistakes before you fix it:
function checkAnswer(choice) {
if (choice = questions[current].answer) {
score + 1;
}
current = current + 1;
}
Ask: "The score never goes up and the answer always counts as right — why?" Then fix it live:
1. if (choice = ...) uses a single = (which assigns, always truthy). Use === to compare: if (choice === questions[current].answer).
2. score + 1 computes a value but throws it away — you must store it: score = score + 1;.
0:58 · Check for understanding (10 min)
Ask these aloud or drop them in the chat. Answer key (for you):
- What is "state" in this app, and which variables hold it? → The app's changing memory —
current(which question) andscore(how many right). - Why do we use
===and not=inside anif? →===compares two values; a single=assigns and would always run the branch. - What does
questions.lengthgive, and why do we comparecurrentto it? → The number of questions (here 3); whencurrentreaches it, there are no questions left, so we show the result.
1:08 · Wrap-up + homework (7 min)
- Ask one student to finish the sentence: "An app's 'state' is…"
- Homework — Finish and personalise your quiz: make sure your quiz runs start to finish, then give it at least 5 questions on a topic you love and restyle it so it looks like yours. Save the Pen — in Session 18 you put this exact app on the live internet and present it. Bring the working link.
Teaching notes
- Correct this misconception: "a real app needs a big framework or a server." Not to start — this whole quiz is three files' worth of code running in the browser. Frameworks come later; the fundamentals here are the same ones underneath them.
- Common errors students hit: forgetting the starting
showQuestion();call,=vs===, not clearingoptionsEl.innerHTML(buttons pile up), a mismatch between an option's text and theanswerstring (so a correct click scores 0), and anidtypo between HTML and JS. The Console names the failing line. - Fast finishers (extension) — add colour feedback and a restart: have the clicked button flash green if right and red if wrong before moving on, using
btn.style.backgroundColor. Then add a "Play again" button on the result screen that resetscurrent = 0andscore = 0and callsshowQuestion(). This introduces the idea of a full app lifecycle — start, play, finish, reset — which every game and quiz app has.
function restart() {
current = 0;
score = 0;
scoreEl.textContent = "Score: 0";
showQuestion();
}
- Low-tech fallback: if devices struggle, build the quiz once on your shared CodePen while students predict each step's behaviour, then have them write their 5 questions and answers on paper (the
questionsarray) ready to type in the next lab.
Vocabulary
| Term | Meaning |
|---|---|
| Array | An ordered list of values, in [ ], counted from 0 |
| Object | A bundle of named values, in { } (like a record) |
| State | The app's changing memory, e.g. current and score |
Loop (for … of) |
Repeats an action once per item in a list |
=== |
Compares two values for exact equality |
Resources
- CodePen — build and run the full app in your browser (free).
- MDN — Arrays — how lists of data work in JavaScript.
- MDN — Manipulating documents (DOM) — creating and updating elements.
- JavaScript.info — Arrays — clear examples and exercises.
Practice set
Extra exercises reinforcing arrays, loops, comparisons, and state — easy to hard. Great for lab time or homework.
1. Predict the output: what prints? → 3. length counts the items in the array.
const fruits = ["apple", "banana", "mango"];
console.log(fruits.length);
2. Predict the output: what is fruits[0] and fruits[2]? → "apple" and "mango" — arrays count from 0, so index 2 is the third item.
3. Predict the output: how many lines print, and what are they? → Three lines: apple, banana, mango — the loop runs once per item.
for (const f of fruits) {
console.log(f);
}
4. Fix the bug: the score never increases. Find the two problems. → Use === to compare, and store the result: if (choice === answer) { score = score + 1; }.
if (choice = answer) {
score + 1;
}
5. Write it: write an array colors holding "red", "green", "blue", then log how many there are. → const colors = ["red", "green", "blue"]; then console.log(colors.length);.
6. Write it: write an object for one quiz question with a text, an options array, and the correct answer. → e.g. { text: "2 + 2?", options: ["4", "5"], answer: "4" }.
7. Trace it (hard): with current = 0 and score = 0, the user answers Q1 right and Q2 wrong (2 questions total). Trace score and current after each answer, and what showResult prints. → After Q1: score = 1, current = 1. After Q2: score stays 1, current = 2; since 2 === length, it shows "Done! You scored 1 / 2".
Going deeper (optional)
For a class that's flying, show that the questions could come from outside the app — the first step toward a data-driven app. Explain that real apps fetch their data instead of hard-coding it, then show the shape of that idea safely with a local array plus a shuffle:
function shuffle(list) {
for (let i = list.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[list[i], list[j]] = [list[j], list[i]]; // swap
}
}
shuffle(questions);
showQuestion();
Land the idea: because the questions are data, not hard-coded HTML, you can shuffle them, add more, or one day load them from a file — without touching the quiz logic at all. This "separate the data from the code" habit is what makes an app easy to grow. Challenge them to also shuffle each question's options so the right answer isn't always in the same spot.
Common mistakes & fixes
- Mistake: forgetting the final
showQuestion();call, so the app loads blank. → Fix: something has to start the app — callshowQuestion()once at the bottom of the code. - Mistake: using
=instead of===in theif. → Fix:===compares; a single=assigns and makes the branch always run. - Mistake:
score + 1on its own line, expecting the score to change. → Fix: store the result:score = score + 1;. - Mistake: the option text doesn't exactly match the
answerstring (a stray space or capital). → Fix: make the correct option identical toanswer, or the right click will score 0. - Mistake: not clearing old buttons, so options from earlier questions stack up. → Fix: set
optionsEl.innerHTML = ""at the start ofshowQuestion()before adding new buttons.
Next session
Session 18 — Ship It: students put this quiz app on the live internet with free hosting, then present it — the unit's build project.