Create a Quiz App with Next JS and Tailwind
Last Updated :
10 Oct, 2024
We’ll explore the process of building a Quiz App utilizing NextJS and Tailwind. The quiz app provides users with a series of multiple-choice questions with options. Users can select the option and move to the next question. At the end, the user will be able to see the analysis of the quiz.
Prerequisites
Approach to Create Quiz App with Next JS and Tailwind:
- Set up the Project by Creating a new Next JS project.
- We will be using the useState hook to manage the quiz state, including the current question, selected answer, and quiz results.
- We will utilize Tailwind to style our Quiz App.
- Create a new QuestionSet.ts file under the Data folder where we will define the questions along with options and answers.
- We will be creating different components for code readability and reusability. Here we will be creating components such as Quiz to render the different questions and ScoreCard to display the result analysis.
- We will be creating interfaces for code organization and type safety.
- The quiz app will start by taking the user's name once we click on the start quiz button page component will render the Quiz component which is responsible for displaying the questions one by one.
- After submitting the test ScoreCard component will be rendered which will display the result analysis including score, correct answers, wrong answers, percentage and status.
Steps to create the Quiz Application:
Step 1: Create a application of NextJS using the following command.
npx create-next-app@latest quiz-app
Step 2: Navigate to project directory
cd quiz-app
Project Structure:
Project StructureUpdated Dependencies:
"dependencies": {
"react": "^18",
"react-dom": "^18",
"next": "14.2.15"
}
Example: This example demonstrates the basic implementation of the Quiz App.
CSS
/* global.css*/
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: #ffffff;
--foreground: #171717;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
JavaScript
// page.tsx
"use client";
import { useState, ChangeEvent } from "react";
import Quiz from "./Components/Quiz";
export default function Home() {
// Using `useState` hooks with appropriate types
const [quizStarted, setQuizStarted] = useState<boolean>(false);
const [name, setName] = useState<string>("");
// Define the function to handle input changes
const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
return (
<div className="container mx-auto mt-10">
<div className="text-center">
<h1 className="text-green-600 text-3xl
font-bold mb-4">
GeekForGeeks
</h1>
<h3 className="text-xl mb-6">
Quiz App
</h3>
</div>
{quizStarted ? (
// Passing `name` to Quiz component, which expects it as a string
<Quiz name={name} />
) : (
<>
<div className="mb-4">
<label
htmlFor="nameInput"
className="block text-lg font-medium text-gray-700">
Enter Your Name:
</label>
<input
type="text"
className="mt-1 block w-full px-4 py-2 border
border-gray-300 rounded-md shadow-sm
focus:outline-none focus:ring-indigo-500
focus:border-indigo-500 sm:text-sm"
id="nameInput"
value={name}
onChange={handleNameChange}
/>
</div>
<button
onClick={() => setQuizStarted(true)}
className="bg-blue-600 text-white px-4
py-2 rounded-md hover:bg-blue-700
transition-colors duration-200"
// Disable button if name is empty or contains only whitespace
disabled={!name.trim()}>
Start Quiz
</button>
</>
)}
</div>
);
}
JavaScript
//Components/Quiz.tsx
import React, { useState } from "react";
import { quiz } from "../Data/QuestionSet";
import ScoreCard from "./ScoreCard";
import { QuizProps, QuizResult, Question } from "../Interfaces/quiz-app";
const Quiz: React.FC<QuizProps> = ({ name }) => {
const [currentQuestionIndex, setCurrentQuestionIndex] = useState<number>(0);
const [selectedAnswer, setSelectedAnswer] = useState<string>("");
const [answerChecked, setAnswerChecked] = useState<boolean>(false);
const [selectedAnswerIndex, setSelectedAnswerIndex] = useState<number | null>(
null
);
const [showResults, setShowResults] = useState<boolean>(false);
const [quizResult, setQuizResult] = useState<QuizResult>({
score: 0,
correctAnswers: 0,
wrongAnswers: 0,
});
const { questions } = quiz;
const { question, answers, correctAnswer } = questions[currentQuestionIndex];
const onAnswerSelected = (answer: string, idx: number) => {
setSelectedAnswerIndex(idx);
setSelectedAnswer(answer);
setAnswerChecked(true);
};
const handleNextQuestion = () => {
if (selectedAnswer === correctAnswer) {
setQuizResult((prev) => ({
...prev,
score: prev.score + 5,
correctAnswers: prev.correctAnswers + 1,
}));
} else {
setQuizResult((prev) => ({
...prev,
wrongAnswers: prev.wrongAnswers + 1,
}));
}
if (currentQuestionIndex !== questions.length - 1) {
setCurrentQuestionIndex((prev) => prev + 1);
} else {
setShowResults(true);
}
setSelectedAnswer("");
setSelectedAnswerIndex(null);
setAnswerChecked(false);
};
return (
<div className="container mx-auto mt-10">
<div>
{!showResults ? (
<div className="bg-white shadow-md rounded-lg p-6">
<h4 className="text-lg font-semibold mb-4">{question}</h4>
<ul className="list-none">
{answers.map((answer, idx) => (
<li
key={idx}
onClick={() => onAnswerSelected(answer, idx)}
className={`p-3 mb-2 border rounded-md
cursor-pointer hover:bg-gray-100 ${
selectedAnswerIndex === idx ? "bg-blue-500 text-white" : ""
}`}
>
{answer}
</li>
))}
</ul>
<div className="flex justify-between mt-6">
<b>
Question {currentQuestionIndex + 1}/{questions.length}
</b>
<button
onClick={handleNextQuestion}
className={`bg-blue-600 text-white
py-2 px-4 rounded-md ${
!answerChecked
? "opacity-50 cursor-not-allowed"
: "hover:bg-blue-700"
}`}
disabled={!answerChecked}
>
{currentQuestionIndex === questions.length - 1
? "Submit"
: "Next Question"}
</button>
</div>
</div>
) : (
<ScoreCard
quizResult={quizResult}
questions={questions}
name={name}
/>
)}
</div>
</div>
);
};
export default Quiz;
JavaScript
//Components/ScoreCard.tsx
import React from "react";
import { ScoreCardProps } from "../Interfaces/quiz-app";
const ScoreCard: React.FC<ScoreCardProps> = ({
quizResult,
questions,
name,
}) => {
const passPercentage = 60;
const percentage = (quizResult.score / (questions.length * 5)) * 100;
const status = percentage >= passPercentage ? "Pass" : "Fail";
return (
<>
<div className="bg-white shadow-md rounded-lg p-6">
<h3 className="text-xl font-semibold mb-4">
Hello, {name}. Here is your Result Analysis
</h3>
<table className="min-w-full table-auto">
<tbody>
<tr>
<td className="border px-4 py-2">Total Questions:</td>
<td className="border px-4 py-2">{questions.length}</td>
</tr>
<tr>
<td className="border px-4 py-2">Total Score:</td>
<td className="border px-4 py-2">{quizResult.score}</td>
</tr>
<tr>
<td className="border px-4 py-2">Correct Answers:</td>
<td className="border px-4 py-2">{quizResult.correctAnswers}</td>
</tr>
<tr>
<td className="border px-4 py-2">Wrong Answers:</td>
<td className="border px-4 py-2">{quizResult.wrongAnswers}</td>
</tr>
<tr>
<td className="border px-4 py-2">Percentage:</td>
<td className="border px-4 py-2">{percentage}%</td>
</tr>
<tr>
<td className="border px-4 py-2">Status:</td>
<td className="border px-4 py-2">{status}</td>
</tr>
</tbody>
</table>
<button
onClick={() => window.location.reload()}
className="bg-blue-600 text-white py-2 px-4
rounded-md mt-4 hover:bg-blue-700">
Restart
</button>
</div>
</>
);
};
export default ScoreCard;
JavaScript
//Data/QuestionSet.ts
import { Quiz } from '../Interfaces/quiz-app';
export const quiz: Quiz = {
questions: [
{
id: 1,
question: 'What does API stand for?',
answers: [
'Application Programming Interface',
'Advanced Programming Interface',
'Application Program Interface',
'Automated Programming Interface',
],
correctAnswer: 'Application Programming Interface',
},
{
id: 3,
question: `Which programming language is often
used for building web servers?`,
answers: ['Java', 'Python', 'JavaScript', 'C#'],
correctAnswer: 'JavaScript',
},
{
id: 4,
question: 'What is the purpose of SQL?',
answers: [
'Styling web pages',
'Querying databases',
'Creating animations',
'Developing mobile apps',
],
correctAnswer: 'Querying databases',
},
{
id: 5,
question: 'What does MVC stand for in web development?',
answers: [
'Model View Controller',
'Model Visual Controller',
'Model View Component',
'Model Visual Component',
],
correctAnswer: 'Model View Controller',
},
],
};
JavaScript
// Interfaces/quiz-app.ts
export interface Question {
id: number;
question: string;
answers: string[];
correctAnswer: string;
}
export interface Quiz {
questions: Question[];
}
export interface QuizResult {
score: number;
correctAnswers: number;
wrongAnswers: number;
}
export interface ScoreCardProps {
quizResult: QuizResult;
questions: Question[];
name: string;
}
export interface QuizProps {
name: string;
}
Start your application using the following command:
npm run dev
Output: Naviage to the URL http://localhost:3000.
Similar Reads
Create a To-Do List App with Next JS and Tailwind To be productive and to remember all the tasks for the day, the To-Do app is very important. In this article, you will see the whole process of creating a to-do app from scratch. This to-do list app includes functionalities like adding new task, editing the task and deleting the task by clicking on
8 min read
Create a Quiz App with Next JS In this article, weâll explore the process of building a Quiz App utilizing NextJS. The quiz app provides users with a series of multiple-choice questions with options. Users can select the option and move to the next question. At the end, the user will be able to see the analysis of the quiz.Output
5 min read
Create a Weather app using React and Tailwind React JS is a very famous library for front-end development. In this article, we will walk through the process of building a weather app using React, a popular JavaScript library for building user interfaces(UI). Here we also use Tailwind CSS, a utility-first CSS framework. Here we also use a weathe
5 min read
Create Dropdowns UI with Next.JS and Tailwind CSS Dropdowns are an essential component of web applications used for navigation, filtering data or selecting items from a list. In this article, weâll explore how to create a clean and responsive dropdown UI using Next.js and Tailwind CSS. Tailwind's utility-first CSS framework allows us to easily styl
3 min read
Create a Quiz App with Timer using HTML CSS and JavaScript Creating a quiz app is an excellent way to learn the fundamentals of web development. In this tutorial, we will build a Quiz App that features a timer, allowing users to take a timed quiz with multiple-choice questions. The app will use HTML for the structure, CSS for styling, and JavaScript for fun
9 min read