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.jsonUsage
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
- 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.
- 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.
- 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
optionsarray changes identity. - 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.
- Reduced motion. Under
prefers-reduced-motion: reducethe shake and the green pop both collapse to instant — the row still flips the colour but skips the animation.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
prompt | ReactNode | required | Prose label rendered before the pills. |
options | readonly { id: string; label: ReactNode }[] | required | Ordered list of options the student can tap. |
correctId | string | required | id of the correct option. |
onAnswer | (event: { id: string; correct: boolean }) => void | required | Fired on every tap — once with correct: true, plus one per wrong attempt. |
disabled | boolean | false | Force-disable taps without resolving. |
aria-label | string | "Inline prediction" | Accessible name for the row. |
className | string | — | Merged onto the outer container. |
Accessibility
- The root is a
role="group"labelled by the prompt span. Inner pills share an implicit radio-group semantic viarole="radio"+aria-checkedon the winning option. - Each pill has an
aria-labelderived from a string label, or falls back to the optionidfor 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 paralleloptions+correctIdxindex pair, a hardcodedtrackHexaccent prop, and reached into the platformuseTimershook for the retry reset. craft-bits collapses to a single{ id, label }option shape with explicitcorrectId, rewires every colour throughcb-accent/cb-successtokens, and inlines the retry reset behindprefers-reduced-motioninstead of pulling a project-wide timer hook.