Unanswered Check

Lists blank, partial and flagged questions before a test or survey is submitted, with jump links and time left.

StopsTest submitted with questions skipped

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/unanswered-check.json

The files land in your project. They're yours to edit.

Usage

unanswered-check-usage.tsx
import { UnansweredCheck, type ExamQuestion } from "@/components/ui/unanswered-check"

<UnansweredCheck
  questions={questions}
  endsAt={endsAt}
  onJump={setCurrent}
  onSubmit={() => new Promise<void>((resolve) => setTimeout(() => (setSubmitted(true), resolve()), 700))}
/>

What it catches

  • Required and optional questions left blank
  • Partly answered questions ("1 of 2 chosen")
  • Questions flagged for review
  • Answers not yet saved to the server
  • Time left and how much each open question gets

Props

UnansweredCheck props
PropTypeDefault
questions* (required)

Every question with its answered, required, flagged and saving state.

ExamQuestion[]—
mode

`exam`: blanks are allowed but cost marks, so submitting with them takes a second click. `survey`: required questions must be answered.

"exam" | "survey""exam"
endsAt

When time runs out. Leave out for untimed tests.

Date | number—
now

Fixed "now" for previews and tests. Defaults to a live clock.

Date | number—
lowTime

Turns the timer amber below this many ms; red below a fifth of it.

number5 * 60_000
onJump* (required)

Go to a question.

(id: string) => void—
onTimeUp

Called once when the time runs out, so the host can auto-submit.

() => void—
onSubmit* (required)

Final submit. Return a promise to show a pending state; a rejection keeps the answers and says so.

() => void | Promise<void>—
heading

Heading of the check.

string"Before you submit"
requiredLabel

Heading for unanswered required questions.

string"Not answered"
optionalLabel

Heading for unanswered optional questions.

string"Optional, not answered"
partialLabel

Heading for partly answered questions.

string"Partly answered"
flaggedLabel

Heading for questions flagged for review.

string"Flagged for review"
allDoneText

Shown when everything is answered.

string"Every question is answered."
autoSubmitText

Templates: `{count}` and `{each}` are filled in.

string"At 0:00 your answers are submitted as they are."
paceText

Time per open question.

string"About {each} for each of the {count} still open."
lastSecondsText

Warning in the last seconds.

string"Submit now: the last seconds can be lost to a slow conne…
submitLabel

Label of the submit button.

string"Submit"
submitWithBlanksLabel

Label when blanks remain.

string"Submit with {count}"
confirmLabel

Label of the second click to submit with blanks.

string"Blanks score 0. Submit anyway"
needRequiredLabel

Label when required questions block submit.

string"Answer {count} required to submit"
savingLabel

Label while answers are saving.

string"Saving {count}…"
pendingLabel

Label while onSubmit runs.

string"Submitting…"
errorText

Shown when onSubmit rejects.

string"Not submitted. Your answers are kept, try again."
goToLabel

Accessible label of a question jump button.

(question: string, note?: string) => string(question, note) => `Go to question ${question}${note ? `…
notAnsweredSrText

Screen-reader note on a flagged question that has no answer.

string", not answered"

* required. Also accepts the native props of <section> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Section labelled by its heading; countdown is role=timer with an aria-label
  • Jump links have aria-labels including notes
  • Status in a polite live region; errors use role=alert

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Enforce required answers and the deadline on the server; accept submissions only once all answers are saved.

  • Only knows the question states you pass
  • Time limits and auto-submit rely on your onTimeUp and server timing

What it stops

Test submitted with questions skipped

Also known as

quiz · exam · test · survey · questionnaire · mcq · assessment · google forms

Dependencies

Pairs well with