Skip to main content

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.

Automated test scoring & grade calculation
Interactive multiple-choice radio question cards
Invisible honeypot (_gotcha) spam trap
Full React / Next.js client component with state
Instant answer sync to Google Sheets & Instructor alerts
Live Form PreviewComponent Sandbox

Architecture Assessment

Multiple-choice quiz with server-side payload capture

Question 1 of 3

What is the primary benefit of a headless form endpoint?

Pre-configured for Backforms endpoint with automated scoring payload
Honeypot anti-spam active
Zero backend needed
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>
  );
}
Replace YOUR_FORM_ID with your Backforms key

Connect this component to your Backforms endpoint

Create a free form endpoint in under 30 seconds. Zero backend servers or databases required.

Get Free Endpoint Key

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.