JSON Viewer

Data Display

Collapsible JSON data tree viewer.

Preview

name: "ParamUI"
version: "1.0.0"
components: 187
categories:
0: "Base"
1: "Form"
2: "Layout"
3: "Navigation"
config:
theme: "auto"
responsive: true

Usage

example.jsx
import { JsonViewer } from "@/components/ui/json-viewer";

export default function Example() {
  return <JsonViewer />;
}

Source Code

Copy this file into components/ui/json-viewer.jsx in your project.

json-viewer.jsx
"use client";

import { forwardRef, useState } from "react";
import { cn } from "@/lib/utils";

const JsonNode = ({ name, value, level = 0 }) => {
  const [open, setOpen] = useState(level < 2);
  const isObj = value && typeof value === "object" && !Array.isArray(value);
  const isArr = Array.isArray(value);
  const isExpandable = isObj || isArr;

  const renderValue = (v) => {
    if (v === null) return <span className="text-muted-foreground">null</span>;
    if (typeof v === "string") return <span className="text-green-600 dark:text-green-400">&quot;{v}&quot;</span>;
    if (typeof v === "number") return <span className="text-blue-600 dark:text-blue-400">{v}</span>;
    if (typeof v === "boolean") return <span className="text-purple-600 dark:text-purple-400">{v.toString()}</span>;
    return null;
  };

  return (
    <div style={{ paddingLeft: level > 0 ? 16 : 0 }}>
      <div className="flex items-center gap-1">
        {isExpandable && (
          <button onClick={() => setOpen(!open)} className="h-4 w-4 shrink-0 text-muted-foreground hover:text-foreground">
            <svg className={cn("h-3 w-3 transition-transform", open && "rotate-90")} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" /></svg>
          </button>
        )}
        {name !== undefined && <span className="text-sm font-medium text-foreground">{name}: </span>}
        {!isExpandable && <span className="text-sm">{renderValue(value)}</span>}
        {isExpandable && !open && <span className="text-xs text-muted-foreground">{isArr ? `Array(${value.length})` : `{${Object.keys(value).length}}`}</span>}
      </div>
      {isExpandable && open && (
        <div>
          {(isArr ? value.map((v, i) => [i, v]) : Object.entries(value)).map(([k, v]) => (
            <JsonNode key={k} name={k} value={v} level={level + 1} />
          ))}
        </div>
      )}
    </div>
  );
};

const JsonViewer = forwardRef(({ className, data, ...props }, ref) => (
  <div ref={ref} className={cn("rounded-md border bg-background p-3 font-mono", className)} {...props}>
    <JsonNode value={data} />
  </div>
));
JsonViewer.displayName = "JsonViewer";

export { JsonViewer };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge