Prediction Gate With Hints

A multi-option prediction checkpoint with an integrated, progressive hint ladder. The student commits to a pick; wrong picks shake and badge red but stay tappable, and the student can reveal one hint at a time between attempts. The gate locks the moment a correct answer lands, and the answer event records the number of attempts and hints used so the parent can weight scoring.

Which traversal visits the root last?

0 / 3 hints
    • Pick an option or reveal a hint to log an event.

    Installation

    npx shadcn@latest add https://craftbits.dev/r/prediction-gate-with-hints.json

    Usage

    import { PredictionGateWithHints } from "@craft-bits/core";
     
    <PredictionGateWithHints
      question="Which traversal visits the root last?"
      options={[
        { id: "pre", label: "Pre-order" },
        { id: "in", label: "In-order" },
        { id: "post", label: "Post-order" },
        { id: "lvl", label: "Level-order" },
      ]}
      correctId="post"
      hints={[
        "It is the only depth-first order where the root prints after its subtrees.",
        "The name refers to where the root sits in the visit sequence.",
        "Post-order: visit left, then right, then the root.",
      ]}
      onAnswer={(e) => console.log(e.id, e.correct, e.attempts, e.hintsUsed)}
      onHintRequest={(level) => console.log("hint", level)}
    />

    Hints are optional — omit the prop for a pure prediction gate:

    <PredictionGateWithHints
      question="Pick the tighter bound."
      options={[
        { id: "a", label: "O(n)" },
        { id: "b", label: "O(n log n)" },
      ]}
      correctId="a"
      onAnswer={handleAnswer}
    />

    Understanding the component

    1. Single-shot once correct. The gate ignores all input after the first correct pick. Wrong picks badge red, shake, and stay tappable so the student can keep trying — no parent state required.
    2. Progressive hints. The hint ladder reveals one rung at a time via a Show a hint button. Each reveal fires onHintRequest(level) so the parent can score how cheaply the answer was earned.
    3. Answer event carries the cost. Every onAnswer call includes attempts (wrong picks before this answer) and hintsUsed (hints revealed at the moment of the answer). Both are zero when the student nails it cold.
    4. Hints are optional. Omit the prop entirely and the hint UI disappears. The component falls back to a plain multi-option prediction gate.
    5. Theme-driven colours. Buttons paint through cb-accent, cb-success, and cb-error tokens — swap the theme and every state repaints with no prop changes. Reduced-motion users get instant feedback with no shake or pop.

    Props

    PropTypeDefaultDescription
    questionReactNoderequiredPrompt rendered above the option buttons.
    optionsreadonly { id: string; label: ReactNode }[]requiredOrdered list of options (2-4 recommended).
    correctIdstringrequiredid of the correct option.
    hintsreadonly ReactNode[]Progressive hint ladder, revealed one rung at a time.
    onAnswer(event) => voidrequiredFired on every tap with { id, correct, attempts, hintsUsed }.
    onHintRequest(level: number) => voidFired when the student reveals a new hint (1-based).
    disabledbooleanfalseForce-disable taps without resolving.
    hintButtonLabelReactNode"Show a hint"Override the hint reveal button label.
    hintExhaustedLabelReactNode"All hints shown"Label once the hint ladder is exhausted.
    aria-labelstring"Prediction with hints"Accessible name for the gate region.
    classNamestringMerged onto the outer container.

    Accessibility

    • The root is a role="group" labelled by the question paragraph. Inner buttons share a role="radiogroup" so screen readers announce them as a paired choice.
    • Each option is a role="radio" with aria-checked set on the winning option. Disabled buttons drop from focus.
    • Every option carries an aria-label derived from a string label, falling back to the option id for non-string labels.
    • The hint list lives inside an aria-live="polite" region so each newly revealed rung is announced without interrupting.
    • Tap feedback collapses to instant under prefers-reduced-motion: reduce — no shake, no scale pop, no hint slide-in.
    • Option buttons clear the 44 x 44 px minimum touch target via min-h-[44px] and horizontal padding.

    Credits

    • Extracted from: algoflashcards (src/lessons/primitives/interaction/PredictionGateWithHints.tsx). The source was a thin wrapper that wired a PredictionGate to a separate HintLadder through a usePredictionGateState reducer, took a hardcoded trackHex colour prop, and depended on per-distractor feedback maps + a project-wide sound-effect registry. craft-bits collapses to a single self-contained component with a flat hints[] ladder, lifts the API to options + correctId + onAnswer + onHintRequest, and rewires every colour through cb-accent / cb-success / cb-error tokens so theme swaps repaint without prop changes.