Weak Patterns Callout
A "needs reinforcement" callout — a warning-tinted panel that surfaces a list of weak or struggling patterns the reader should revisit. Each pattern is rendered as a chip with an optional score readout and optional link. Pair it with a generic "items below mastery threshold" filter and let the component decide whether to render itself (empty arrays short-circuit to nothing).
Preview
Needs reinforcement
Patterns trending below your mastery threshold this week.
- Two-pointer34%
- Sliding window41%
- Binary search bounds52%
Customize
Callout
0
3
Installation
npx shadcn@latest add https://craftbits.dev/r/weak-patterns-callout.jsonUsage
import { WeakPatternsCallout } from "@craft-bits/core";
<WeakPatternsCallout
patterns={[
{ label: "Two-pointer", score: 0.34, href: "/topics/two-pointer" },
{ label: "Sliding window", score: 0.41 },
]}
cta={<a href="/review">Review now</a>}
/>Drop the score for a flat list of names, or pass an empty array to short-circuit:
<WeakPatternsCallout patterns={weakItems} />Switch the surface palette via the tone prop:
<WeakPatternsCallout tone="info" patterns={items} />
<WeakPatternsCallout tone="error" patterns={items} />Understanding the component
- Empty arrays render nothing. The component checks
patterns.length === 0before any DOM is emitted. Pass the raw weak-items array and skip the conditional at the call site. - Tone drives the palette.
warning(default),info, anderroreach derive their background, border, and chip tint from the cb semantic tokens — no inline colours. - Pattern shape is flat. Each chip is
{ label, id?, score?, href? }.idis only needed when labels may collide. Whenhrefis present, the chip renders as a real anchor and picks up focus-visible affordances. - Scores are formatted, not raw. Pass a
0–1value topattern.scoreand the component renders it as0–100%. OverrideformatScoreto swap the unit (e.g. raw count, "low") or returnnullto suppress. - Chip stagger respects reduced motion. Each chip enters with a small
yshift staggered bySTAGGER(40ms). Underprefers-reduced-motion: reducethe entry collapses to a static fade.
Variants
Default — warning tone
<WeakPatternsCallout
patterns={[
{ label: "Two-pointer", score: 0.34 },
{ label: "Sliding window", score: 0.41 },
]}
/>Info tone with CTA
<WeakPatternsCallout
tone="info"
title="Drift detected"
description="Three patterns are trending down."
patterns={[
{ label: "Binary search", score: 0.62, href: "#bs" },
{ label: "DFS", score: 0.71, href: "#dfs" },
]}
cta={<a href="#review">Review</a>}
/>Error tone, no scores
<WeakPatternsCallout
tone="error"
title="Failing fast"
patterns={[{ label: "Heap math" }, { label: "Trie traversal" }]}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
patterns | readonly { label: string; id?: string; score?: number; href?: string }[] | required | Items to surface. Empty array renders nothing. |
title | ReactNode | "Needs reinforcement" | Headline copy. |
description | ReactNode | — | Optional sub-line below the title. |
tone | 'warning' | 'info' | 'error' | 'warning' | Surface palette. |
cta | ReactNode | — | Trailing action node on the header row. |
icon | ComponentType<{ className?: string }> | null | built-in alert glyph | Leading icon. Pass null to suppress. |
formatScore | (score: number) => ReactNode | 0–1 → 0–100% | Score formatter. Return null to suppress. |
className | string | — | Merged onto the root via cn(). |
...rest | HTMLAttributes<HTMLDivElement> | — | Any other root attribute. |
Accessibility
- The root is announced as a polite live region (
role="region"+aria-live="polite") so chip-list updates are surfaced to assistive tech without interrupting the user. - Linked chips render as real anchors with
focus-visiblering affordances drawn from the active tone token. - The leading icon is
aria-hidden="true"— the title carries the semantic weight. - Chip stagger and entry motion are suppressed under
prefers-reduced-motion: reduce; only opacity fades remain. - All three tone colours read from the cb semantic token system (
--cb-warning,--cb-info,--cb-error) and clear WCAG AA contrast on the default surface tokens.
Credits
- Extracted from:
algoflashcards(src/platform/ui/WeakPatternsCallout.tsx). The original was a thin wrapper over the project'sAlert/Badgeshadcn components with a hard-coded "Needs Reinforcement" string,bg-warning/Ninline tokens, and apatterns: string[]API. craft-bits drops the shadcnAlertshell, replaces every inline colour withcb-*semantic classes, generalises the pattern shape to{ label, id?, score?, href? }, adds tone variants, a configurable title / description / CTA / icon, score formatting, and a staggered chip entry that respectsprefers-reduced-motion.