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).

DP value row, 7 cells, 2 filled, 2 transitions.
Customize
Shape
7
Playback
800 ms

Installation

npx shadcn@latest add https://craftbits.dev/r/dp-value-row.json

Usage

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

  1. One cell per entry. values.length cells render, in order. The cell at index i shows values[i] — a number, a string ("∞", "-1"), or ? when the entry is null.
  2. 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 rides SPRINGS.smooth so values pop in.
  3. Highlight pulse. Indices in highlighted get 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.
  4. Controlled or uncontrolled. The highlighted set follows the Radix pattern. Pass highlighted for full control; pass defaultHighlighted for an uncontrolled initial set; pass neither for a static, never-pulsing row.
  5. Per-cell tones. Each cell can override the resting accent. accent (the default) reads as "currently relevant"; success as "settled"; warning as "tentative"; danger as "discarded"; muted as "out of scope".
  6. Labels. labels[i] replaces the default index label above the cell. Omit the array (or pass undefined for a given index) to fall back to the cell index.
  7. Reduced motion. When prefers-reduced-motion: reduce is set, the cell-state transition collapses to duration: 0 and the highlight pulse is disabled — tone changes snap instead of breathing.

Props

PropTypeDefaultDescription
values(number | string | null)[]requiredCurrent DP entries. null renders the placeholder.
highlightednumber[]Controlled set of indices to pulse.
defaultHighlightednumber[][]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.
placeholderstring"?"Glyph for empty cells.
transitionTransitionSPRINGS.smoothCell-state transition.
classNamestringMerged onto the root via cn().

Accessibility

  • The outer element is role="group" with a hidden summary like DP value row, 6 cells, 3 filled. so screen readers hear the row's state at a glance.
  • Each cell is role="img" with an aria-label of {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), and data-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, a hex prop carrying the lesson's track color, and an inline editable mode 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-hex palette so consumers can colour-code algorithm state.