DP Value Row
A horizontal strip of equal-width cells, one per index, designed for dynamic-programming visualizations where a recurrence fills a flat array (dp[i], memo[i], dist[v]) one cell at a time. Each cell renders the current entry — a number, a string, or a ? placeholder when the value is null — and a highlighted set pulses an accent border around the cells the outer animation is currently filling.
Generic over the underlying algorithm: works for tabulation, memoization, BFS distances, parent pointers, or any other index-keyed table the visualization wants to expose. Per-cell tones and labels let callers colour-code state ("settled" vs "frontier") and rename indices (dp[i-1], A, i=3).
Installation
npx shadcn@latest add https://craftbits.dev/r/dp-value-row.jsonUsage
import { DPValueRow } from "@craft-bits/core";
<DPValueRow values={[0, 1, 1, 2, 3, null]} highlighted={[5]} />Pass labels to rename each column:
<DPValueRow
values={[0, 1, 1, 2, 3, 5]}
labels={["dp[0]", "dp[1]", "dp[2]", "dp[3]", "dp[4]", "dp[5]"]}
/>Mix tones to colour-code algorithm state (frontier vs settled):
<DPValueRow
values={[0, 4, 7, null, null]}
highlighted={[2]}
tones={["success", "success", "accent", undefined, undefined]}
/>Drive the highlight set from outside (Radix-style controlled mode):
const [highlighted, setHighlighted] = useState([0]);
<DPValueRow values={values} highlighted={highlighted} />Understanding the component
- One cell per entry.
values.lengthcells render, in order. The cell at indexishowsvalues[i]— a number, a string ("∞","-1"), or?when the entry isnull. - Filled vs empty. Filled cells get an accent fill, accent border, and accent ink; empty cells get a muted background and the
?placeholder. The transition between empty and filled ridesSPRINGS.smoothso values pop in. - Highlight pulse. Indices in
highlightedget a 1.2s breathing border in the cell's tone — the canonical "this is the cell the algorithm is filling right now" treatment. Pass an empty array (the default) for a static row. - Controlled or uncontrolled. The
highlightedset follows the Radix pattern. Passhighlightedfor full control; passdefaultHighlightedfor an uncontrolled initial set; pass neither for a static, never-pulsing row. - Per-cell tones. Each cell can override the resting accent.
accent(the default) reads as "currently relevant";successas "settled";warningas "tentative";dangeras "discarded";mutedas "out of scope". - Labels.
labels[i]replaces the default index label above the cell. Omit the array (or passundefinedfor a given index) to fall back to the cell index. - Reduced motion. When
prefers-reduced-motion: reduceis set, the cell-state transition collapses toduration: 0and the highlight pulse is disabled — tone changes snap instead of breathing.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
values | (number | string | null)[] | required | Current DP entries. null renders the placeholder. |
highlighted | number[] | — | Controlled set of indices to pulse. |
defaultHighlighted | number[] | [] | Uncontrolled initial highlight set. |
labels | (string | undefined)[] | — | Per-cell label above the cell. Defaults to the index. |
tones | (DPValueRowTone | undefined)[] | — | Per-cell tone: accent | success | warning | danger | muted. |
placeholder | string | "?" | Glyph for empty cells. |
transition | Transition | SPRINGS.smooth | Cell-state transition. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The outer element is
role="group"with a hidden summary likeDP value row, 6 cells, 3 filled.so screen readers hear the row's state at a glance. - Each cell is
role="img"with anaria-labelof{label}: {value}or{label}: empty, so a screen-reader user can read the array entry-by-entry. - Each cell exposes
data-state(filled/empty),data-tone(the active tone), anddata-highlight(true/false) so consumer apps can hook custom styles or assistive tooling. - Colour is never the only signal — empty cells render the placeholder glyph alongside the muted background; tones layer on a ring and a fill so highlighted cells stay legible for colourblind users.
- Motion respects
prefers-reduced-motion: reduce— cell-state transitions and the highlight pulse both collapse to instant swaps when the user opts out.
Credits
- Extracted from:
AlgoFlashcards(src/lessons/primitives/graph/DPValueRow.tsx). The source was Dijkstra-specific (Map<nodeId, value>keyed on graph nodes, ahexprop carrying the lesson's track color, and an inlineeditablemode that wired a typed-input "predict the value" interaction). The library extract drops the lesson chrome — the editable typed-input lives in lesson code, not in the primitive — and accepts a flat(number | string | null)[]so the same component covers tabulation, memoization, BFS distances, and parent-pointer rows. Per-cell tones replace the single-hexpalette so consumers can colour-code algorithm state.