Project: Quiz App

In the previous lesson, we built a weather app that fetched live data from an API. Now let’s build a quiz app that ties together everything you have practiced so far: an array of objects holds the questions, the DOM shows them on screen, events react to clicks, and a few variables keep track of where the player is.

🎯 What We’ll Build

We are building a multiple-choice quiz. The app shows one question at a time with a few answer buttons. When the player picks an answer, the app checks if it is right, adds to the score if it is, and moves on to the next question. After the last question, it shows a final score instead of another question.

The whole thing runs on three pieces of information that change as the player works through the quiz: which question they are on, what their score is, and whether the quiz has finished. Those changing values are called the app’s state.

What is state?

State is just the data that describes “where things are right now.” In this quiz, the current question number and the score are the state. When the state changes, we redraw the screen to match.

🧱 The HTML

The page needs a spot for the question, a spot for the answer options, a button to move forward, and a spot to show the score. Each part gets an id so the JavaScript can find it later.

index.html
<div id="quiz">
<div id="question">Question goes here</div>
<div id="options"></div>
<button id="next-btn">Next</button>
<div id="score"></div>
</div>

Let’s walk through what each element is for:

  • The outer <div id="quiz"> wraps the whole quiz so we have one container to style and position.
  • <div id="question"> is where the question text goes. The placeholder text gets replaced as soon as the JavaScript runs.
  • <div id="options"> starts empty because we build the answer buttons in JavaScript, one fresh set per question.
  • <button id="next-btn"> lets the player move to the next question once they have answered.
  • <div id="score"> also starts empty and only fills in at the end, when the quiz is complete.

⚙️ The JavaScript

Here is the full quiz logic. Read through it once, then we will walk through each part below.

quiz-app.js
const questions = [
{
question: "Which keyword declares a value that cannot be reassigned?",
options: ["var", "let", "const", "static"],
correctAnswer: "const",
},
{
question: "What does the '===' operator check?",
options: ["Value only", "Value and type", "Type only", "Nothing"],
correctAnswer: "Value and type",
},
{
question: "Which method adds an item to the end of an array?",
options: ["push", "pop", "shift", "slice"],
correctAnswer: "push",
},
];
const questionEl = document.getElementById("question");
const optionsEl = document.getElementById("options");
const nextBtn = document.getElementById("next-btn");
const scoreEl = document.getElementById("score");
let currentIndex = 0;
let score = 0;
function renderQuestion() {
const current = questions[currentIndex];
questionEl.textContent = current.question;
optionsEl.innerHTML = "";
current.options.forEach((option) => {
const button = document.createElement("button");
button.textContent = option;
button.addEventListener("click", () => handleAnswer(option));
optionsEl.appendChild(button);
});
}
function handleAnswer(selected) {
const current = questions[currentIndex];
if (selected === current.correctAnswer) {
score++;
}
nextBtn.disabled = false;
}
function showFinalScore() {
questionEl.textContent = "Quiz complete!";
optionsEl.innerHTML = "";
nextBtn.style.display = "none";
scoreEl.textContent = `You scored ${score} out of ${questions.length}.`;
}
nextBtn.addEventListener("click", () => {
currentIndex++;
if (currentIndex < questions.length) {
renderQuestion();
} else {
showFinalScore();
}
});
renderQuestion();

Let’s go through this top to bottom, one section at a time:

  • The questions array holds the whole quiz. Each item is an object with three properties: the question text, an options array of possible answers, and the correctAnswer that one of those options must match.
  • The four getElementById lines grab the question, options, button, and score elements once and save them in const variables so we never have to look them up again.
  • let currentIndex = 0 and let score = 0 are the state: the question we are on and how many the player has gotten right. They start at zero and change as the quiz runs.
  • renderQuestion draws the current question. It reads questions[currentIndex] to find which question to show, sets the question text, and clears any old buttons out of the options div with optionsEl.innerHTML = "".
  • Inside renderQuestion, the forEach loop builds a fresh button for each option, gives it a click listener that calls handleAnswer with that button’s text, and appends it to the options div.
  • handleAnswer runs when the player clicks an option. It compares the selected answer against the question’s correctAnswer, adds one to score if they match, and enables the Next button so the player can move on.
  • showFinalScore swaps the question for a completion message, clears the options, hides the Next button, and prints the final tally in the score div.
  • The nextBtn listener bumps currentIndex up by one, then calls renderQuestion if there are still questions left or showFinalScore once we have run past the last one.
  • The final renderQuestion() call kicks everything off by drawing the very first question when the page loads.

Why clear the options div?

Setting optionsEl.innerHTML = "" at the start of renderQuestion removes the previous question’s buttons. Without it, old answers would pile up on screen every time you moved forward.

🚀 Try It Yourself!

The quiz works, but there is plenty of room to make it your own. Try these enhancements.

  1. Add a countdown timer. Start a setInterval when each question renders, and call handleAnswer with a wrong answer (or skip ahead) when the time runs out. Clear the interval whenever the player answers.
  2. Shuffle the questions so the quiz is different each time. Write a small function that reorders the questions array before the first renderQuestion call.
  3. Add more questions to the array. Because the code loops over questions.length, you do not have to change any logic, just add new objects.
  4. Highlight the chosen answer. In handleAnswer, color the clicked button green if it was right and red if it was wrong before moving on.

The array drives everything

Notice how adding a question never means touching the loop or the buttons. The data describes the quiz, and the code just reads the data. That separation is what makes the app easy to grow.

🧩 What You’ve Learned

  • ✅ How to store structured data as an array of objects, each with its own properties
  • ✅ How to render the current item to the DOM and rebuild it on every step
  • ✅ How to attach event listeners to buttons you create in JavaScript
  • ✅ How to track state with variables like currentIndex and score
  • ✅ How to end a flow by showing a final result instead of more content

🚀 What’s Next?

You have now combined data, the DOM, events, and state into one working app. Next we will track money instead of answers. Let’s continue to Expense Tracker.

Share & Connect