Componenteditors1.17 KB gzipZero dependencies
JSON Inspector
Collapsible colored API response viewer.
Preview
Live Preview
API response
“stub”: “BB-90210”{“row”: “C”,“number”: 12}“valid”: trueInstallation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add json-inspectorOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { JsonInspector } from "@/components/ui/json-inspector";
<JsonInspector value={{ stub: "BB-1" }} />Usage guidance
Use JSON Inspector when a ticket stub surface needs Collapsible colored API response viewer. Keep props minimal and prefer composition with sibling stubs.
Avoid JSON Inspector for long form flows or dense data grids where a dedicated layout block fits better.
Source code
json-inspector.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface JsonInspectorProps extends React.HTMLAttributes<HTMLDivElement> {
value: unknown;
defaultExpanded?: boolean;
maxDepth?: number;
label?: string;
}
function renderValue(value: unknown, depth: number, maxDepth: number): React.ReactNode {
if (value === null) return <span className="text-muted-foreground">null</span>;
if (value === undefined) return <span className="text-muted-foreground">undefined</span>;
const t = typeof value;
if (t === "string") return <span className="text-accent">“{value as string}”</span>;
if (t === "number" || t === "bigint") return <span className="text-foreground">{String(value)}</span>;
if (t === "boolean") return <span className="text-accent">{String(value)}</span>;
if (Array.isArray(value)) {
if (value.length === 0) return <span className="text-muted-foreground">[]</span>;
if (depth >= maxDepth) return <span className="text-muted-foreground">Array({value.length}) […]</span>;
return (
<span>
[
{value.map((v, i) => (
<span key={i} className="block pl-4">
{renderValue(v, depth + 1, maxDepth)}
{i < value.length - 1 ? <span className="text-muted-foreground">,</span> : null}
</span>
))}
]
</span>
);
}
if (t === "object") {
const entries = Object.entries(value as Record<string, unknown>);
if (entries.length === 0) return <span className="text-muted-foreground">{"{}"}</span>;
if (depth >= maxDepth) return <span className="text-muted-foreground">{"{…}"}</span>;
return (
<span>
{"{"}
{entries.map(([k, v], i) => (
<span key={k} className="block pl-4">
<span className="text-foreground">“{k}”</span>
<span className="text-muted-foreground">: </span>
{renderValue(v, depth + 1, maxDepth)}
{i < entries.length - 1 ? <span className="text-muted-foreground">,</span> : null}
</span>
))}
{"}"}
</span>
);
}
return <span className="text-muted-foreground">{String(value)}</span>;
}
function Collapsible({ k, children, startOpen }: { k: string; children: React.ReactNode; startOpen: boolean }) {
const [open, setOpen] = React.useState(startOpen);
return (
<span className="block">
<button
type="button"
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
className="cursor-pointer font-mono text-xs text-muted-foreground hover:text-foreground"
>
{open ? "▾" : "▸"} {k}
</button>
{open ? <span className="block pl-4">{children}</span> : <span className="text-muted-foreground"> …</span>}
</span>
);
}
export function JsonInspector({ value, defaultExpanded = true, maxDepth = 4, label, className, ...props }: JsonInspectorProps) {
const top: [string, unknown][] =
value !== null && typeof value === "object" && !Array.isArray(value)
? Object.entries(value as Record<string, unknown>)
: [["root", value]];
return (
<div className={cn("w-full overflow-x-auto rounded-lg border border-border bg-card p-4 font-mono text-xs leading-relaxed", className)} {...props}>
{label ? (
<p className="mb-2 text-[10px] uppercase tracking-widest text-muted-foreground">{label}</p>
) : null}
{top.map(([k, v]) =>
typeof v === "object" && v !== null ? (
<Collapsible key={k} k={k} startOpen={defaultExpanded}>
{renderValue(v, 1, maxDepth)}
</Collapsible>
) : (
<span key={k} className="block">
<span className="text-foreground">“{k}”</span>
<span className="text-muted-foreground">: </span>
{renderValue(v, 1, maxDepth)}
</span>
),
)}
</div>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| value | unknown | Value to inspect (required). |
| defaultExpanded | boolean | Expand all initially (default true). |
| maxDepth | number | Nesting cap (default 4). |