Inline Prediction

A one-line predict-then-reveal row designed to sit inside a sentence. The student taps a small pill instead of breaking out into a full prediction gate, so it composes with code-trace annotations, tree narration, stack walk-throughs, and any other reading-rhythm interaction. Wrong picks shake and auto-reset; the correct pick locks the row with a green pop.

We pop the top of the stack. The path array becomes and the top pointer moves to.

  • Tap a pill to log an answer.

Installation

npx shadcn@latest add https://craftbits.dev/r/inline-prediction.json

Usage

import { InlinePrediction } from "@craft-bits/core";
 
<p>
  We pop the top and the path array{" "}
  <InlinePrediction
    prompt="becomes"
    options={[
      { id: "a", label: "[1]" },
      { id: "b", label: "[0]" },
      { id: "c", label: "[]" },
    ]}
    correctId="a"
    onAnswer={(e) => console.log(e.id, e.correct)}
  />
  .
</p>

Swap the options to ask the next question — the row resets automatically when the options array identity changes:

<InlinePrediction
  prompt="moves to"
  options={nextOptions}
  correctId={nextCorrectId}
  onAnswer={handleAnswer}
/>

Understanding the component

  1. Reading rhythm first. The row renders as inline-flex with baseline alignment, so it sits inside a paragraph without breaking the line. Use it where a full prediction gate would be too heavyweight.
  2. Single-shot once correct. The component locks after the first correct tap. Wrong taps shake (~600ms) and then re-enable the row so the student can retry — no parent state required.
  3. Resets on options change. Re-using the row for the next question is a single prop swap. The internal pick + solved state clear automatically when the options array changes identity.
  4. Quiz only. Unlike the binary prediction gate, this primitive is built for "what value comes next" questions where there is one correct answer. There is no "personal prediction" mode.
  5. Reduced motion. Under prefers-reduced-motion: reduce the shake and the green pop both collapse to instant — the row still flips the colour but skips the animation.

Props

PropTypeDefaultDescription
promptReactNoderequiredProse label rendered before the pills.
optionsreadonly { id: string; label: ReactNode }[]requiredOrdered list of options the student can tap.
correctIdstringrequiredid of the correct option.
onAnswer(event: { id: string; correct: boolean }) => voidrequiredFired on every tap — once with correct: true, plus one per wrong attempt.
disabledbooleanfalseForce-disable taps without resolving.
aria-labelstring"Inline prediction"Accessible name for the row.
classNamestringMerged onto the outer container.

Accessibility

  • The root is a role="group" labelled by the prompt span. Inner pills share an implicit radio-group semantic via role="radio" + aria-checked on the winning option.
  • Each pill has an aria-label derived from a string label, or falls back to the option id for non-string labels (icons, JSX).
  • The correct pill keeps focusable state after solve so screen-reader review keeps working; the wrong pills drop from focus once the row is locked.
  • Tap feedback collapses to instant under prefers-reduced-motion: reduce — no shake, no scale pop.
  • Pills clear a 22 px minimum height with horizontal padding — small enough to live in prose, but large enough for finger taps when wrapped to its own line on mobile.

Credits

  • Extracted from: algoflashcards (src/lessons/primitives/interaction/InlinePrediction.tsx). The source took a parallel options + correctIdx index pair, a hardcoded trackHex accent prop, and reached into the platform useTimers hook for the retry reset. craft-bits collapses to a single { id, label } option shape with explicit correctId, rewires every colour through cb-accent / cb-success tokens, and inlines the retry reset behind prefers-reduced-motion instead of pulling a project-wide timer hook.