Inline Array
A compact array-as-chip primitive. Renders a flat (number | string)[] as a single bordered strip of cells sized to flow inline with the surrounding text — the right glyph for prose like "the frontier is now …" or "we've seen …" where a full-width array visualization would be overkill.
Cells fade-and-pop in when added, fade out when removed, and slide between positions when the array re-orders. Optional highlighted indices and a paired highlightTone mark the cell the algorithm is currently touching.
Frontier Array, 3 elements: 1, 2, 3.123 grows by one each tick.
Installation
npx shadcn@latest add https://craftbits.dev/r/inline-array.jsonUsage
import { InlineArray } from "@craft-bits/core";
<p>
The frontier so far is <InlineArray values={[1, 2, 3]} />.
</p>Mark the head of the array with a contrasting tone:
<InlineArray values={[1, 2, 3, 4]} highlighted={[3]} highlightTone="success" />Pin a stable key when the array contains duplicates so re-orders animate cleanly:
<InlineArray
values={frontier.map((node) => node.label)}
getKey={(_, i) => frontier[i].id}
/>Render with no motion (e.g. inside non-animated copy):
<InlineArray values={[3, 6, 1, 4]} animate={false} />Understanding the component
- One bordered strip. The outer
spancarries the array's border, background tint, andborder-radius. Each cell is an inline-flex child that paints its own color and divider — so the whole array reads as a single chip in running text. - Inline sizing. The strip is
h: 1.55emand usesalign-middlewithtabular-numsso digits stay column-aligned and the chip's baseline matches the surrounding line of text. Resize the prose and the chip resizes too. - Tone via CSS variables.
tonepicks acb-*semantic var (accent/success/warning/danger/muted); the border, fill, and ink all derive from that one variable viacolor-mix(…)so the chip themes correctly under light and dark mode. - Highlighted cells. Indices in
highlightedswitch tohighlightTone(defaults to the resting tone). A highlighted cell gets a stronger tinted fill on top of the shared strip background — useful for marking the head, the cursor, or the last touched index. - Stable keys. By default the cell's React key is
String(value)— fine for unique-valued arrays. Arrays with duplicates should passgetKeyso re-orders animate as motion instead of unmount/remount. - Entry, exit, reorder. Cells wrap in
AnimatePresence mode="popLayout"so additions pop in, removals fade out, and reorders glide (via Motion'slayoutprop).initial={false}skips the mount-time stagger. - Empty state. Pass an empty array and the chip renders an empty-set glyph (
{ }) at the same size — the right rest state for an array that "hasn't been built yet." - Reduced motion. When
prefers-reduced-motion: reduceis set, the cell transition collapses toduration: 0— additions and removals snap.
Variants
A static array in prose:
<p>
Sort <InlineArray values={[5, 2, 8, 1]} /> by ascending key.
</p>A typed-token array with mixed strings:
<InlineArray values={["a", "b", "c"]} tone="muted" />A growing frontier with a pulsing head:
<InlineArray
values={[0, 1, 1, 2, 3]}
highlighted={[4]}
highlightTone="warning"
/>The empty state — useful as the initial render before the array is built:
<InlineArray values={[]} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
values | (number | string)[] | required | Values rendered inside each cell, left → right. |
highlighted | number[] | — | Indices to render in highlightTone instead of the resting tone. |
tone | InlineArrayTone | "accent" | Resting tone — accent | success | warning | danger | muted. |
highlightTone | InlineArrayTone | same as tone | Tone for highlighted cells. |
getKey | (value, index) => string | number | String(value) | Stable React key per cell — pass for duplicate-valued arrays. |
emptyPlaceholder | string | "{ }" | Glyph rendered when values is empty. |
animate | boolean | true | Set false to disable enter/exit motion (snap transitions). |
transition | Transition | SPRINGS.snap | Override the cell transition. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The outer element is
role="img"with a hidden summary likeArray, 4 elements: 1, 2, 3, 4.so screen readers hear the array's contents instead of reading each cell's digit in isolation. - Each cell carries
data-tone(the active tone) anddata-highlight(true/false) so consumer apps can hook custom styles or assistive tooling. - The empty state renders the placeholder glyph alongside an
aria-label="Empty array"so the chip stays meaningful when it has no content. - Color is never the only signal — highlighted cells get an extra tinted fill on top of the shared strip background, and the value's digit is the primary cue regardless of tone.
- Motion respects
prefers-reduced-motion: reduce— cells snap in and out instead of springing.
Credits
- Extracted from:
craftingattention(app/src/components/ui/richtext-array.tsx). The source parsed a literaltextstring ([3,6],{1,2,3},[[3,6],[1,4]]) and branched on three shapes plus an empty-set glyph; the library extract drops the parser and accepts a typedvalues: (number | string)[]so the same component covers any array source — typed arrays, sets, frontiers, paths — without round-tripping through string. The 2D-array branch lives in lesson code as a<div>ofInlineArrays; the inline-prose chip is the single primitive shipped here. The hardcoded success-green palette was replaced with thecb-*tone system so the chip themes correctly under any palette.