All questions and review
Show every question together or paginate a quiz, edit selections, review answers, and submit once using the existing headless API.
Try the quiz
Answer in any order. Change single choices, toggle multiple choices, or switch the number of questions per page without losing answers. Correctness and scores appear only after submission.
Implementation
This is a custom headless layout; the default Quiz component continues to show one question at a time. Install react-quiz-component, then copy the component, quiz.ts, and examples.css into the same directory. Next.js applications need a client boundary; the preview mounts in the browser.
Render state.questionStates rather than just the current question. allowNavigation permits targeting any question, and revealAnswerOnSubmit keeps choices editable until submission. Each click first calls goToQuestion(index) and, only if it succeeds, selectAnswer(answerNumber). Both actions see the latest session within the same React event.
Pagination only changes which questions are displayed. state.canSubmit checks the entire quiz, including hidden pages, and requires exactly the requested number of multiple selections. The summary and question outcomes are available internally before submission; this example deliberately renders them only after completion. It uses text questions without a timer; add image or audio rendering separately when your data requires it.
'use client';
import { useState } from 'react';
import { useQuiz } from 'react-quiz-component';
import { quiz } from './quiz';
import './examples.css';
export default function AllQuestionsExample() {
const { state, actions } = useQuiz({ quiz, allowNavigation: true, revealAnswerOnSubmit: true });
const [pageSize, setPageSize] = useState(quiz.questions.length);
const [page, setPage] = useState(0);
const pageCount = Math.ceil(state.questions.length / pageSize);
return (
<section className="headless-demo" aria-label="Reviewable quiz">
{state.status === 'invalid' && <p role="alert">{state.errors.join(' ')}</p>}
{state.status === 'idle' && <>
<h2>{quiz.quizTitle}</h2>
<p>Answer the questions, review your choices, then submit.</p>
<button onClick={actions.start}>Start quiz</button>
</>}
{state.status === 'active' && <>
<label>Questions per page{' '}
<select value={pageSize} onChange={(event) => { setPageSize(Number(event.target.value)); setPage(0); }}>
<option value={state.questions.length}>All questions</option>
{state.questions.slice(1).map((_, index) => <option key={index + 1} value={index + 1}>{index + 1}</option>)}
</select>
</label>
{state.questionStates.slice(page * pageSize, (page + 1) * pageSize).map(({ question, index, answers }) => (
<fieldset key={index} className="question-group">
<legend>{index + 1}. {question.question}</legend>
<p>Select {Array.isArray(question.correctAnswer) ? question.correctAnswer.length : 1} answer(s).</p>
<div className="answers">
{answers.map((answer) => <button key={answer.answerNumber}
disabled={answer.disabled} aria-pressed={answer.selected}
onClick={() => {
// Actions share the latest session even within one React event.
if (actions.goToQuestion(index).ok) actions.selectAnswer(answer.answerNumber);
}}>
{answer.value}
</button>)}
</div>
</fieldset>
))}
{pageCount > 1 && <nav aria-label="Question pages">
<button disabled={page === 0} onClick={() => setPage(page - 1)}>Previous page</button>
<span>Page {page + 1} of {pageCount}</span>
<button disabled={page + 1 === pageCount} onClick={() => setPage(page + 1)}>Next page</button>
</nav>}
<p role="status">{state.canSubmit ? 'Review your answers, then submit.' : 'Select the requested number of answers for every question.'}</p>
<button disabled={!state.canSubmit} onClick={actions.submitQuiz}>Submit quiz</button>
</>}
{state.status === 'completed' && <>
<output>Score: {state.summary.correctPoints} / {state.summary.totalPoints}</output>
<ol>
{state.questionStates.map(({ question, index, answers, outcome }) => <li key={index}>
<strong>{question.question}</strong>
<p>Your answers: {answers.filter((answer) => answer.selected).map((answer) => answer.value).join(', ')} — {outcome}</p>
</li>)}
</ol>
<button onClick={() => { actions.reset(); setPage(0); }}>Try again</button>
</>}
</section>
);
}
Custom styles
.headless-demo {
display: grid;
gap: 16px;
}
.headless-demo h2 {
font-size: 1.2rem;
font-weight: 600;
}
.headless-demo .answers {
display: grid;
gap: 8px;
}
.headless-demo .question-group {
display: grid;
min-inline-size: 0;
gap: 8px;
padding: 16px;
border: 1px solid var(--color-fd-border, #d4d4d8);
border-radius: 8px;
}
.headless-demo .question-group legend {
max-inline-size: 100%;
padding-inline: 4px;
font-weight: 600;
}
.headless-demo button,
.headless-demo select {
border: 1px solid var(--color-fd-border, #d4d4d8);
border-radius: 8px;
padding: 8px 12px;
margin: 4px 8px 4px 0;
cursor: pointer;
background: var(--color-fd-background, #fff);
color: var(--color-fd-foreground, #18181b);
}
.headless-demo button:hover {
background: var(--color-fd-muted, #f4f4f5);
}
.headless-demo button[aria-pressed='true'] {
border-color: var(--color-fd-primary, #2563eb);
background: var(--color-fd-accent, #eff6ff);
}
.headless-demo button:disabled {
opacity: 0.65;
cursor: default;
}
.headless-demo :focus-visible {
outline: 2px solid var(--color-fd-primary, #2563eb);
outline-offset: 3px;
}
Quiz data
import type { Quiz } from 'react-quiz-component';
export const quiz: Quiz = {
quizTitle: 'React essentials',
quizSynopsis: 'Two questions about React hooks and rendering.',
questions: [
{
question: 'Which hook stores local state?',
questionType: 'text',
answerSelectionType: 'single',
answers: ['useState', 'useEffect', 'useRef'],
correctAnswer: '1',
point: 10,
messageForCorrectAnswer: 'Correct! useState stores component state.',
messageForIncorrectAnswer: 'useState is the hook for local state.',
explanation: 'useState returns the current value and a setter.',
},
{
question: 'Which APIs render React content? Pick two.',
questionType: 'text',
answerSelectionType: 'multiple',
answers: ['createRoot', 'renderToString', 'querySelector'],
correctAnswer: [1, 2],
point: 20,
explanation:
'createRoot renders in the browser; renderToString renders HTML on the server.',
},
],
};
Provider and context
Share one quiz session across separate question, timer, navigation, and results components using QuizProvider and useQuizContext. Try pausing the timer, revisiting questions, and filtering results, then explore the complete implementation and quiz data.
2.1.0
Per-question timers, audio questions, early submission, optional correct-answer highlighting, improved answer feedback, and expanded interactive examples.