Card Feedback
The response panel that sits below a problem-explainer card or quiz prompt after the learner picks. Pinned to one of four statuses — idle, correct, incorrect, partial — each driving the left rail color, the icon tint, the title color, and the politeness of the announced aria-live region.
Preview
Feedback
Pick an option to see feedback.
Customize
Status
Options
Installation
npx shadcn@latest add https://craftbits.dev/r/card-feedback.jsonUsage
import { CardFeedback } from "@craft-bits/edu";
<CardFeedback
status="correct"
message="The denominator covers every position, so the weights always sum to 1."
explanation="That is what makes the output a proper probability distribution."
action={{ label: "Continue", onClick: handleContinue }}
/>A bare placeholder before the learner has interacted:
<CardFeedback status="idle" message="Pick an option to see feedback." />Anatomy
- Status rail — a 3px left border painted with the tone color (
--cb-success/--cb-error/--cb-warning/ neutral). The fastest skim signal. - Status icon — a circular badge with a tinted background and an outline glyph (check / cross / warning dot). Hide via
hideIconor replace viaicon. - Title — a small uppercase label painted in the tone color. Defaults to
Correct/Not quite/Almost there/Feedback. Pass''to suppress. - Message — long-form body text rendered with
text-wrap: pretty. Hot-swaps on status change without a layout jump. - Explanation — optional smaller, muted paragraph rendered underneath the message for "why this is right/wrong" context.
- Action slot — an optional inline button (
Continue,Try again, etc.) painted in the same tone. Pass one action; render multi-button rows insidemessageif you need more.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
status | 'idle' | 'correct' | 'incorrect' | 'partial' | 'idle' | Drives the rail color, icon tint, title color, and aria-live tone. |
title | ReactNode | tone-derived | Headline above the message. Pass '' to suppress. |
message | ReactNode | — | Long-form explanation. Rendered with text-wrap: pretty. |
explanation | ReactNode | — | Deeper "why" context rendered underneath the message in a smaller, muted tone. |
action | CardFeedbackAction | — | Optional inline button (label, onClick, disabled, aria-label). |
hideIcon | boolean | false | Suppress the leading status icon. |
icon | ReactNode | tone-derived glyph | Override the default outline icon. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The root is a
<section role="status">witharia-livematched to the status —assertiveforincorrect,politeforcorrect/partial,offforidle. - The icon and status badge are
aria-hidden="true"; the status meaning is conveyed by the title text, so screen-reader users hear the wordsCorrect/Not quite/Almost thererather than the icon shape. - The action button enforces a 44px minimum hit area and shows a visible
:focus-visiblering keyed to--cb-accent. - Color is never the only channel — the title text changes alongside the rail color, so the panel still reads correctly in monochrome or to color-blind viewers.
Credits
- Extracted from:
AlgoFlashcards(src/games/runtime/CardFeedback.tsx). Stripped the ConvexuseMutation, thepatternId/gameType/cardIdprops, and the thumbs-up/down rating flow — generalized into a presentational panel that takes astatus+message+explanation+action. The dev-only comment input dropped (out of scope for a library primitive).