State Inspector
Compact JSON-style tree viewer for any JavaScript value. Renders strings, numbers, booleans, null/undefined, dates, regexes, functions, arrays, and objects — each with its own colour — and lets you click to expand or collapse any object or array node. Designed for "what's in this state right now" debug panels in lesson-style interactive demos.
"id": 42,
"name": "Ada Lovelace",
"admin": true,
"lastSeen": null
},
0: 98,
1: 87,
2: 91,
3: 100
],
"beta": true,
"experimental": false
},
"notes": "first run"
}
Customize
Value
nested
Depth
4
Installation
npx shadcn@latest add https://craftbits.dev/r/state-inspector.jsonUsage
import { StateInspector } from "@craft-bits/core";
<StateInspector value={{ count: 1, items: ["a", "b"], active: true }} />Understanding the component
- Recursive renderer.
valueis narrowed to one of a dozenValueKinds —string,number,boolean,null,undefined,date,regexp,function,symbol,array,object,circular— bytypeof,Array.isArray, andinstanceofchecks. Each kind has its own renderer and colour. - Expand / collapse. Object and array nodes render as a
<button>row with a chevron. Clicking toggles the children's container betweenhiddenandblock. The chevron itself usesSPRINGS.snapfor a 0°→90° rotation — quick, no overshoot. - Cycle detection. Each recursion passes a
ReadonlySet<object>of ancestors. When a node's value is already in that set, the kind becomes"circular"and it renders as[Circular]instead of recursing forever — try the circular sample above. - Depth-aware default.
defaultExpandedonly opens nodes whose depth is belowmaxDepth. A deeply-nested blob therefore renders fast — deep levels stay collapsed until clicked. - Monospace + tabular nums. The whole tree uses
font-cb-monoandtabular-numsfor array indices so numeric columns align.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | unknown | required | Any JavaScript value. Objects and arrays render as expandable trees. |
defaultExpanded | boolean | true | Whether the root object/array starts expanded. |
maxDepth | number | 4 | Maximum nesting depth that auto-expands; deeper nodes stay collapsed until clicked. |
wrapAt | number | 60 | Single-line collapsed previews wrap when they would exceed this width. |
className | string | — | Merged onto the root <div>. |
Accessibility
- The root element has
role="tree"so assistive tech recognises the structure. - Each expandable row is a
<button>witharia-expanded={open}. - Buttons are reachable by Tab and toggle with Enter/Space (native button semantics).
- Focus ring uses
--cb-accentviafocus-visible:outline. - Animations are limited to the chevron's rotation; the disclosure itself is an instant DOM toggle, so users with
prefers-reduced-motionaren't blocked from interacting.
Credits
- Extracted from:
terminal-dreams(src/components/recipe-lab/StateInspector.tsx). The library version is a re-architecture — the source rendered a flat label/value list, the library version is a fully recursive JSON tree with expand/collapse, cycle detection, and a wider set of value kinds.