Multiple-Choice Quiz & Assessment Form
A technical knowledge evaluation and candidate skills assessment form styled with Tailwind CSS in an indigo-slate theme. Collects participant identity, records multiple-choice responses, calculates automated test scores, and dispatches full answer breakdowns to your instructors or hiring team via Backforms email alerts and Google Sheets.
Architecture Assessment
Multiple-choice quiz with server-side payload capture
What is the primary benefit of a headless form endpoint?
style="color:#9ece6a;">"use client";
import { useState } from style="color:#9ece6a;">"react";
import { Award, HelpCircle } from style="color:#9ece6a;">"lucide-react";
export default function MultipleChoiceQuizForm() {
const [participantName, setParticipantName] = useState(style="color:#9ece6a;">"");
const [participantEmail, setParticipantEmail] = useState(style="color:#9ece6a;">"");
const [answers, setAnswers] = useState<style="color:#f7768e;font-weight:600;">Record<string, string>>({
q1: style="color:#9ece6a;">"a",
q2: style="color:#9ece6a;">"a",
q3: style="color:#9ece6a;">"a",
});
const [score, setScore] = useState<style="color:#f7768e;font-weight:600;">number>(0);
const [status, setStatus] = useState<style="color:#9ece6a;">"idle" | style="color:#9ece6a;">"loading" | style="color:#9ece6a;">"success" | style="color:#9ece6a;">"error">(style="color:#9ece6a;">"idle");
const [errorMessage, setErrorMessage] = useState(style="color:#9ece6a;">"");
const correctAnswers: Record<string, string> = {
q1: style="color:#9ece6a;">"a",
q2: style="color:#9ece6a;">"a",
q3: style="color:#9ece6a;">"a",
};
async function handleSubmit(e: React.FormEvent<style="color:#f7768e;font-weight:600;">HTMLFormElement>) {
e.preventDefault();
setStatus(style="color:#9ece6a;">"loading");
setErrorMessage(style="color:#9ece6a;">"");
let calculated = 0;
if (answers.q1 === correctAnswers.q1) calculated += 1;
if (answers.q2 === correctAnswers.q2) calculated += 1;
if (answers.q3 === correctAnswers.q3) calculated += 1;
setScore(calculated);
const form = e.currentTarget;
const formData = new FormData(form);
formData.set(style="color:#9ece6a;">"score", calculated.toString());
formData.set(style="color:#9ece6a;">"maxScore", style="color:#9ece6a;">"3");
formData.set(style="color:#9ece6a;">"percentage", Math.round((calculated / 3) * 100) + style="color:#9ece6a;">"%");
try {
style=style="color:#9ece6a;">"color:#565f89;font-style:italic;">// Replace YOUR_FORM_ID with your Backforms endpoint ID from app.backforms.com
const response = await fetch(style="color:#9ece6a;">"https:style="color:#565f89;font-style:italic;style="color:#9ece6a;">">//backforms.com/f/YOUR_FORM_ID", {
method: style="color:#9ece6a;">"POST",
headers: {
Accept: style="color:#9ece6a;">"application/json",
},
body: formData,
});
if (response.ok) {
setStatus(style="color:#9ece6a;">"success");
} else {
const data = await response.json().catch(() => null);
setErrorMessage(data?.error || style="color:#9ece6a;">"Quiz submission failed. Please try again.");
setStatus(style="color:#9ece6a;">"error");
}
} catch {
setErrorMessage(style="color:#9ece6a;">"Network error. Please check your internet connection.");
setStatus(style="color:#9ece6a;">"error");
}
}
return (
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"flex flex-col items-center justify-center min-h-[500px] p-4">
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"w-full max-w-md bg-gradient-to-b from-[#0e1626] to-[#090e18] border border-indigo-500/30 rounded-2xl p-6 sm:p-7 shadow-2xl text-zinc-100">
<style="color:#f7768e;font-weight:600;">h2 className=style="color:#9ece6a;">"text-xl sm:text-2xl font-extrabold text-white mb-1">
Technical Assessment Quiz
</style="color:#f7768e;font-weight:600;">h2>
<style="color:#f7768e;font-weight:600;">p className=style="color:#9ece6a;">"text-xs text-zinc-400 mb-5 leading-relaxed">
Answer the multiple-choice questions below to test your understanding.
</style="color:#f7768e;font-weight:600;">p>
{status === style="color:#9ece6a;">"success" ? (
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"p-5 bg-indigo-950/60 border border-emerald-500/40 text-emerald-300 rounded-xl text-center space-y-2">
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"size-10 mx-auto rounded-full bg-emerald-950/70 border border-emerald-500/40 flex items-center justify-center text-emerald-400">
<style="color:#f7768e;font-weight:600;">Award className=style="color:#9ece6a;">"size-5" />
</style="color:#f7768e;font-weight:600;">div>
<style="color:#f7768e;font-weight:600;">p className=style="color:#9ece6a;">"font-extrabold text-lg text-white">
Final Score: {score}/3 ({Math.round((score / 3) * 100)}%)
</style="color:#f7768e;font-weight:600;">p>
<style="color:#f7768e;font-weight:600;">p className=style="color:#9ece6a;">"text-xs text-zinc-300">
Thank you, {participantName}! Your answers have been recorded and sent to the grader.
</style="color:#f7768e;font-weight:600;">p>
<style="color:#f7768e;font-weight:600;">button
type=style="color:#9ece6a;">"button"
onClick={() => setStatus(style="color:#9ece6a;">"idle")}
className=style="color:#9ece6a;">"mt-3 px-4 py-1.5 bg-indigo-600 hover:bg-indigo-500 text-white font-bold rounded-lg text-xs transition cursor-pointer"
>
Retake Quiz
</style="color:#f7768e;font-weight:600;">button>
</style="color:#f7768e;font-weight:600;">div>
) : (
<style="color:#f7768e;font-weight:600;">form onSubmit={handleSubmit} className=style="color:#9ece6a;">"space-y-4">
{style=style="color:#9ece6a;">"color:#565f89;font-style:italic;">/* Invisible Honeypot Spam Trap */}
<style="color:#f7768e;font-weight:600;">input
type=style="color:#9ece6a;">"text"
name=style="color:#9ece6a;">"_gotcha"
style={{ display: style="color:#9ece6a;">"none" }}
tabIndex={-1}
autoComplete=style="color:#9ece6a;">"off"
/>
{status === style="color:#9ece6a;">"error" && (
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"p-3 bg-red-950/80 border border-red-500/50 text-red-300 text-xs rounded-lg">
{errorMessage}
</style="color:#f7768e;font-weight:600;">div>
)}
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"grid grid-cols-1 sm:grid-cols-2 gap-2">
<style="color:#f7768e;font-weight:600;">div>
<style="color:#f7768e;font-weight:600;">label className=style="color:#9ece6a;">"block text-xs font-medium text-zinc-300 mb-1" htmlFor=style="color:#9ece6a;">"quiz-name">
Participant Name
</style="color:#f7768e;font-weight:600;">label>
<style="color:#f7768e;font-weight:600;">input
id=style="color:#9ece6a;">"quiz-name"
name=style="color:#9ece6a;">"participantName"
type=style="color:#9ece6a;">"text"
required
placeholder=style="color:#9ece6a;">"Taylor Candidate"
value={participantName}
onChange={(e) => setParticipantName(e.target.value)}
className=style="color:#9ece6a;">"w-full bg-[#182338] text-white border border-indigo-500/25 rounded-lg px-3 py-1.5 text-xs placeholder:text-zinc-500 focus:outline-none focus:border-indigo-400 transition"
/>
</style="color:#f7768e;font-weight:600;">div>
<style="color:#f7768e;font-weight:600;">div>
<style="color:#f7768e;font-weight:600;">label className=style="color:#9ece6a;">"block text-xs font-medium text-zinc-300 mb-1" htmlFor=style="color:#9ece6a;">"quiz-email">
Email Address
</style="color:#f7768e;font-weight:600;">label>
<style="color:#f7768e;font-weight:600;">input
id=style="color:#9ece6a;">"quiz-email"
name=style="color:#9ece6a;">"participantEmail"
type=style="color:#9ece6a;">"email"
required
placeholder=style="color:#9ece6a;">"taylor@edu.com"
value={participantEmail}
onChange={(e) => setParticipantEmail(e.target.value)}
className=style="color:#9ece6a;">"w-full bg-[#182338] text-white border border-indigo-500/25 rounded-lg px-3 py-1.5 text-xs placeholder:text-zinc-500 focus:outline-none focus:border-indigo-400 transition"
/>
</style="color:#f7768e;font-weight:600;">div>
</style="color:#f7768e;font-weight:600;">div>
{style=style="color:#9ece6a;">"color:#565f89;font-style:italic;">/* Question 1 */}
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"p-3 bg-[#131d2e] border border-indigo-500/20 rounded-xl space-y-2">
<style="color:#f7768e;font-weight:600;">p className=style="color:#9ece6a;">"text-xs font-semibold text-white flex items-center gap-1.5">
<style="color:#f7768e;font-weight:600;">HelpCircle className=style="color:#9ece6a;">"size-3.5 text-indigo-400 shrink-0" />
<style="color:#f7768e;font-weight:600;">span>1. What is the primary benefit of a headless form backend?</style="color:#f7768e;font-weight:600;">span>
</style="color:#f7768e;font-weight:600;">p>
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"space-y-1.5">
{[
{ key: style="color:#9ece6a;">"a", label: style="color:#9ece6a;">"Zero server code or database setup required" },
{ key: style="color:#9ece6a;">"b", label: style="color:#9ece6a;">"Requires writing and maintaining custom SQL" },
].map((opt) => (
<style="color:#f7768e;font-weight:600;">label
key={opt.key}
className=style="color:#9ece6a;">"flex items-center gap-2 p-2 rounded-lg text-xs cursor-pointer transition bg-[#182338]/60 text-zinc-300 hover:border-zinc-700"
>
<style="color:#f7768e;font-weight:600;">input
type=style="color:#9ece6a;">"radio"
name=style="color:#9ece6a;">"q1_answer"
value={opt.key}
checked={answers.q1 === opt.key}
onChange={() => setAnswers((prev) => ({ ...prev, q1: opt.key }))}
className=style="color:#9ece6a;">"accent-indigo-500"
/>
<style="color:#f7768e;font-weight:600;">span>{opt.label}</style="color:#f7768e;font-weight:600;">span>
</style="color:#f7768e;font-weight:600;">label>
))}
</style="color:#f7768e;font-weight:600;">div>
</style="color:#f7768e;font-weight:600;">div>
{style=style="color:#9ece6a;">"color:#565f89;font-style:italic;">/* Question 2 */}
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"p-3 bg-[#131d2e] border border-indigo-500/20 rounded-xl space-y-2">
<style="color:#f7768e;font-weight:600;">p className=style="color:#9ece6a;">"text-xs font-semibold text-white flex items-center gap-1.5">
<style="color:#f7768e;font-weight:600;">HelpCircle className=style="color:#9ece6a;">"size-3.5 text-indigo-400 shrink-0" />
<style="color:#f7768e;font-weight:600;">span>2. How does the invisible honeypot trap prevent bot spam?</style="color:#f7768e;font-weight:600;">span>
</style="color:#f7768e;font-weight:600;">p>
<style="color:#f7768e;font-weight:600;">div className=style="color:#9ece6a;">"space-y-1.5">
{[
{ key: style="color:#9ece6a;">"a", label: style="color:#9ece6a;">"Hidden input traps bots without interrupting humans" },
{ key: style="color:#9ece6a;">"b", label: style="color:#9ece6a;">"Forces users to solve complex visual puzzles" },
].map((opt) => (
<style="color:#f7768e;font-weight:600;">label
key={opt.key}
className=style="color:#9ece6a;">"flex items-center gap-2 p-2 rounded-lg text-xs cursor-pointer transition bg-[#182338]/60 text-zinc-300 hover:border-zinc-700"
>
<style="color:#f7768e;font-weight:600;">input
type=style="color:#9ece6a;">"radio"
name=style="color:#9ece6a;">"q2_answer"
value={opt.key}
checked={answers.q2 === opt.key}
onChange={() => setAnswers((prev) => ({ ...prev, q2: opt.key }))}
className=style="color:#9ece6a;">"accent-indigo-500"
/>
<style="color:#f7768e;font-weight:600;">span>{opt.label}</style="color:#f7768e;font-weight:600;">span>
</style="color:#f7768e;font-weight:600;">label>
))}
</style="color:#f7768e;font-weight:600;">div>
</style="color:#f7768e;font-weight:600;">div>
<style="color:#f7768e;font-weight:600;">button
type=style="color:#9ece6a;">"submit"
disabled={status === style="color:#9ece6a;">"loading"}
className=style="color:#9ece6a;">"w-full mt-2 bg-gradient-to-r from-indigo-500 via-indigo-600 to-blue-600 hover:from-indigo-400 hover:to-blue-500 text-white font-bold py-2.5 px-4 rounded-xl transition cursor-pointer shadow-lg shadow-indigo-600/25 disabled:opacity-60 flex items-center justify-center gap-2"
>
<style="color:#f7768e;font-weight:600;">Award className=style="color:#9ece6a;">"size-4" />
<style="color:#f7768e;font-weight:600;">span>{status === style="color:#9ece6a;">"loading" ? style="color:#9ece6a;">"Grading & Submitting..." : style="color:#9ece6a;">"Submit Quiz for Grading"}</style="color:#f7768e;font-weight:600;">span>
</style="color:#f7768e;font-weight:600;">button>
</style="color:#f7768e;font-weight:600;">form>
)}
</style="color:#f7768e;font-weight:600;">div>
</style="color:#f7768e;font-weight:600;">div>
);
}Connect this component to your Backforms endpoint
Create a free form endpoint in under 30 seconds. Zero backend servers or databases required.
Frequently Asked Questions & Technical Integration
How are multiple-choice answers graded and stored in Backforms?
Backforms stores all submitted answers (e.g. q1_answer, q2_answer, score) as structured key-value fields. You can calculate scores on the client or let Google Sheets auto-grade responses using spreadsheet formulas.
Can I send quiz results automatically to the participant's email?
Yes! Backforms custom autoresponder templates allow you to include dynamic confirmation emails with the participant's score, pass/fail status, and explanation notes.
How does the invisible honeypot prevent automated quiz submission spam?
Automated form bots typically fill every input they discover. The hidden _gotcha input is invisible to human test-takers; when Backforms detects data in it, the submission is silently dropped.