Every admin tool eventually needs to show raw JSON — a webhook payload, an API response, an audit log. JSON.stringify(data, null, 2) in a <pre> works until the payload is 2MB of nested arrays, and the "proper" tree viewers often make it worse by mounting a React component for every node in the document up front. Ten thousand nodes, ten thousand components, one frozen tab.
Velocity X's standard-json-tree-viewer is built on the only rule that scales: render what's expanded, summarise what isn't.
The Money Pattern
A collapsed node renders one row — its key, its type, and a count — regardless of what's inside. Children don't exist in the React tree until expansion:
function Node({ k, value, depth }) {
const [open, setOpen] = useState(depth < 2); // auto-open shallow levels
const isObj = value !== null && typeof value === 'object';
if (!isObj) return <Leaf k={k} value={value} />;
const size = Array.isArray(value) ? value.length : Object.keys(value).length;
return (
<div>
<button aria-expanded={open} onClick={() => setOpen(o => !o)}>
{k}: {Array.isArray(value) ? `[${size}]` : `{${size}}`}
</button>
{open && Object.entries(value).map(([ck, cv]) =>
<Node key={ck} k={ck} value={cv} depth={depth + 1} />
)}
</div>
);
}
The open && is the entire performance model: a 2MB payload with everything collapsed is a few dozen components, not ten thousand. Depth-based auto-open (levels 0–1) gives orientation without the mount cost.
The Catch
The feature that separates a viewer people tolerate from one they like: copy path. Right-clicking a node should hand you payload.items[3].customer.email — because the next thing anyone does with a JSON viewer is write code against the shape they just found. Copy-value matters too, but copy-path is the one nobody ships.
Watch the types at the edges: null vs undefined vs "null" (string) must render distinctly, big numbers past MAX_SAFE_INTEGER arrive already mangled if you parsed with JSON.parse — if your IDs are int64, keep them as strings server-side.
The Verdict
A JSON viewer is a lazy tree plus two copy buttons, and the lazy part is non-negotiable at real payload sizes. The finished one lives in Velocity X's Standard Data category next to the sortable table and the inline-editable grid — application surfaces, source you own.









