You’re looking to create a JavaScript quiz tutorial! This is a fantastic way to apply core JavaScript concepts like DOM manipulation, events, arrays, objects, and conditional logic. We’ll build a simple multiple-choice quiz from scratch.
The Core Components of a JavaScript Quiz
A typical quiz involves:
- Questions and Answers: Stored as JavaScript data.
- Display Logic: Showing one question at a time.
- User Interaction: Handling answer selections.
- Scoring Logic: Checking answers and tallying points.
- Feedback: Telling the user if their answer was correct/incorrect.
- Navigation: Moving to the next question.
- Results: Displaying the final score.
HTML Structure for Our Quiz
Let’s set up the basic HTML. We’ll need a container for the quiz, elements to display the question, answer choices, a “next” button, and a place for the score.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Quiz</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f4f7f6; margin: 0; }
.quiz-container {
background-color: #ffffff;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
width: 90%;
max-width: 600px;
text-align: center;
}
h1 { color: #333; margin-bottom: 25px; }
#question-display {
font-size: 1.4em;
margin-bottom: 25px;
color: #555;
min-height: 60px; /* To prevent layout shift */
}
.answers-container {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 25px;
}
.answer-button {
background-color: #e0e0e0;
border: 1px solid #ccc;
padding: 12px 15px;
font-size: 1em;
cursor: pointer;
border-radius: 8px;
transition: background-color 0.2s, transform 0.1s;
text-align: left; /* Align text to the left for better readability */
}
.answer-button:hover {
background-color: #d0d0d0;
transform: translateY(-2px);
}
.answer-button.selected {
background-color: #c9e6ff;
border-color: #007bff;
font-weight: bold;
}
.answer-button.correct {
background-color: #d4edda;
border-color: #28a745;
font-weight: bold;
}
.answer-button.incorrect {
background-color: #f8d7da;
border-color: #dc3545;
font-weight: bold;
}
#feedback {
margin-top: -10px; /* Adjust spacing */
margin-bottom: 15px;
font-weight: bold;
min-height: 20px; /* Prevent layout shift */
}
#next-button {
background-color: #007bff;
color: white;
padding: 12px 25px;
font-size: 1.1em;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.2s;
}
#next-button:hover {
background-color: #0056b3;
}
#next-button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
#score-display {
font-size: 1.8em;
color: #28a745;
margin-top: 30px;
}
</style>
</head>
<body>
<div class="quiz-container">
<h1>JavaScript Quiz!</h1>
<p id="question-display">Question will appear here.</p>
<div class="answers-container" id="answers">
</div>
<p id="feedback"></p>
<button id="next-button" disabled>Next Question</button>
<p id="score-display" style="display: none;"></p>
</div>
<script>
// JavaScript quiz logic will go here
</script>
</body>
</html>
JavaScript Quiz Logic
Now, let’s write the JavaScript to power our quiz.
JavaScript
document.addEventListener('DOMContentLoaded', function() {
// 1. Quiz Data
const quizQuestions = [
{
question: "What does JS stand for?",
answers: [
{ text: "Just Script", correct: false },
{ text: "JavaScript", correct: true },
{ text: "Jazzy Script", correct: false },
{ text: "Junior Script", correct: false }
]
},
{
question: "Which keyword is used to declare a constant variable in JS?",
answers: [
{ text: "var", correct: false },
{ text: "let", correct: false },
{ text: "const", correct: true },
{ text: "static", correct: false }
]
},
{
question: "What is the correct way to write an array in JavaScript?",
answers: [
{ text: "{1, 2, 3}", correct: false },
{ text: "(1, 2, 3)", correct: false },
{ text: "[1, 2, 3]", correct: true },
{ text: "<1, 2, 3>", correct: false }
]
},
{
question: "Which method is used to add an element to the end of an array?",
answers: [
{ text: "append()", correct: false },
{ text: "push()", correct: true },
{ text: "addToEnd()", correct: false },
{ text: "last()", correct: false }
]
}
];
// 2. DOM Element References
const questionDisplay = document.getElementById('question-display');
const answersContainer = document.getElementById('answers');
const feedbackParagraph = document.getElementById('feedback');
const nextButton = document.getElementById('next-button');
const scoreDisplay = document.getElementById('score-display');
// 3. Quiz State Variables
let currentQuestionIndex = 0;
let score = 0;
let selectedAnswerButton = null; // To keep track of the selected answer
// 4. Function to Load a Question
function loadQuestion() {
// Reset previous state
resetQuizState();
if (currentQuestionIndex < quizQuestions.length) {
const questionData = quizQuestions[currentQuestionIndex];
questionDisplay.textContent = `${currentQuestionIndex + 1}. ${questionData.question}`;
questionData.answers.forEach(answer => {
const button = document.createElement('button');
button.textContent = answer.text;
button.classList.add('answer-button');
button.dataset.correct = answer.correct; // Store correct state as a data attribute
answersContainer.appendChild(button);
button.addEventListener('click', selectAnswer);
});
nextButton.disabled = true; // Disable next button until an answer is selected
} else {
// Quiz finished
showResults();
}
}
// 5. Function to Handle Answer Selection
function selectAnswer(event) {
// If an answer was already selected, deselect it visually
if (selectedAnswerButton) {
selectedAnswerButton.classList.remove('selected');
}
const clickedButton = event.target;
clickedButton.classList.add('selected');
selectedAnswerButton = clickedButton; // Store reference to the selected button
// Enable the next button as an answer has been selected
nextButton.disabled = false;
feedbackParagraph.textContent = ""; // Clear any previous feedback
// Optional: Provide immediate feedback if desired (but for a quiz, usually after 'Next')
// const isCorrect = JSON.parse(clickedButton.dataset.correct);
// feedbackParagraph.textContent = isCorrect ? "Correct!" : "Incorrect!";
// feedbackParagraph.style.color = isCorrect ? "green" : "red";
}
// 6. Function to Check Answer and Advance
function checkAnswerAndAdvance() {
if (!selectedAnswerButton) {
alert("Please select an answer before proceeding!");
return;
}
// Disable all answer buttons to prevent re-selection
Array.from(answersContainer.children).forEach(button => {
button.disabled = true;
});
const isCorrect = JSON.parse(selectedAnswerButton.dataset.correct); // Convert string 'true'/'false' to boolean
// Provide visual feedback (correct/incorrect styling)
if (isCorrect) {
selectedAnswerButton.classList.add('correct');
feedbackParagraph.textContent = "Correct!";
feedbackParagraph.style.color = "green";
score++;
} else {
selectedAnswerButton.classList.add('incorrect');
feedbackParagraph.textContent = "Incorrect.";
feedbackParagraph.style.color = "red";
// Also show the correct answer
Array.from(answersContainer.children).forEach(button => {
if (JSON.parse(button.dataset.correct)) {
button.classList.add('correct'); // Highlight the correct answer
}
});
}
nextButton.textContent = (currentQuestionIndex === quizQuestions.length - 1) ? "Show Results" : "Next Question";
nextButton.disabled = false; // Ensure next button is enabled to advance
// Wait a moment before loading the next question or showing results
setTimeout(() => {
currentQuestionIndex++;
loadQuestion();
}, 1500); // Wait 1.5 seconds before moving to next question/results
}
// 7. Function to Reset Quiz State for Next Question
function resetQuizState() {
answersContainer.innerHTML = ''; // Clear previous answer buttons
feedbackParagraph.textContent = ''; // Clear feedback
feedbackParagraph.style.color = ''; // Reset feedback color
nextButton.textContent = 'Next Question';
nextButton.disabled = true;
selectedAnswerButton = null; // Reset selected answer
}
// 8. Function to Show Final Results
function showResults() {
questionDisplay.style.display = 'none';
answersContainer.style.display = 'none';
feedbackParagraph.style.display = 'none';
nextButton.style.display = 'none';
scoreDisplay.textContent = `Quiz Complete! You scored ${score} out of ${quizQuestions.length}!`;
scoreDisplay.style.display = 'block';
}
// Event Listener for the Next Button
nextButton.addEventListener('click', checkAnswerAndAdvance);
// Initial load of the first question
loadQuestion();
});
Explanation of the JavaScript Logic:
quizQuestions
Array: This array of objects holds all our quiz data. Each object has aquestion
string and ananswers
array. Eachanswer
object hastext
and acorrect
boolean.- DOM References: We get references to the HTML elements we need to manipulate.
- State Variables:
currentQuestionIndex
: Tracks which question we’re currently on.score
: Keeps track of the user’s correct answers.selectedAnswerButton
: A variable to store the button element the user clicked, so we can access its properties later.
loadQuestion()
:- Clears previous answers and feedback.
- Checks if there are more questions. If not, it calls
showResults()
. - Updates
questionDisplay
with the current question. - Iterates through
questionData.answers
usingforEach()
. - For each answer, it
document.createElement('button')
, sets itstextContent
, adds theanswer-button
CSS class, and importantly, sets adata-correct
attribute (a custom attribute to store the correct state) which makes it easy to retrieve the correctness. - Appends the created button to the
answersContainer
. - Attaches a
click
event listener to each answer button, callingselectAnswer
. - Disables the
nextButton
until an answer is selected.
selectAnswer(event)
:- This function runs when an answer button is clicked.
event.target
refers to the specific button clicked. - It manages the visual
selected
class, ensuring only one button looks selected at a time. - Enables the
nextButton
because an answer has now been chosen.
- This function runs when an answer button is clicked.
checkAnswerAndAdvance()
:- First, it checks if an answer was actually selected.
- It disables all answer buttons to prevent further clicks for the current question.
- It retrieves the
correct
state from theselectedAnswerButton.dataset.correct
(remember toJSON.parse
it as data attributes are always strings). - Updates the
score
if correct. - Applies
correct
orincorrect
CSS classes for visual feedback and updates thefeedbackParagraph
. - If the answer was incorrect, it also highlights the correct answer’s button.
- Changes the text of the
nextButton
to “Show Results” if it’s the last question. - Uses
setTimeout()
to pause briefly (1.5 seconds) before incrementingcurrentQuestionIndex
and callingloadQuestion()
again, giving the user time to see the feedback.
resetQuizState()
: Clears the previous answers, feedback, and resets the “next” button’s state, preparing the UI for the next question.showResults()
: Hides the quiz elements and displays the final score.- Event Listener for
nextButton
: ThenextButton
‘sclick
event directly callscheckAnswerAndAdvance()
. - Initial Call:
loadQuestion()
is called onceDOMContentLoaded
to start the quiz.
This setup provides a robust, interactive, and user-friendly JavaScript quiz experience. You can easily extend it by adding more questions, different types of feedback, timers, or more complex scoring mechanisms.