資料展示

JSON 樹檢視器

可收合的 JSON 樹:型別配色、路徑複製、展開動畫。

以等寬字型遞迴渲染任何 JSON 資料:字串綠、數字藍、布林橘、null 紅,物件與陣列可展開收合(高度動畫加箭頭旋轉,並顯示項數摘要),滑過任一列即可一鍵複製該節點的路徑或值,適合 API 除錯面板與開發者工具。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add json-tree-viewer

還沒有專案,或安裝遇到問題?看快速開始 →

JSON Tree Viewer 是用 React、Tailwind CSS 與 Motion 做的 JSON 檢視器(JSON viewer)元件,圖示來自 lucide-react。傳入一份 JsonValue 資料就會渲染成可收合的樹狀結構,每一列都能複製該節點的存取路徑(例如 $.user.tags[0])或格式化後的值。

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

2
編輯中的呼叫預設屬性
<JsonTreeViewer/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

適用情境

  • API 除錯面板或後台的「原始回應」分頁,讓開發者展開查看巢狀欄位。
  • Webhook、事件紀錄或稽核日誌的 payload 檢視。
  • 設定檔、feature flag 或 CMS 欄位的唯讀預覽。
  • 開發者文件中展示範例回應,讀者可以直接複製欄位路徑。
  • 不適合:要呈現的是資料夾與檔案結構時,改用 File Tree。

安裝

npx webberui@latest add https://webberui.com/r/json-tree-viewer.json

或在 components.json 設定 registries 後,改用 @webberui/json-tree-viewer 安裝。

使用

import { JsonTreeViewer } from "@/components/ui/json-tree-viewer";

<JsonTreeViewer
  data={{ name: "Webber", stars: 1024, tags: ["ui", "react"], beta: false }}
  defaultExpandDepth={2}
  rootName="$"
/>

範例

從 API 載入資料

在 Client Component 中取得資料後傳給 data;載入完成前可以先顯示一段提示文字。

"use client";

import * as React from "react";
import { JsonTreeViewer, type JsonValue } from "@/components/ui/json-tree-viewer";

export function ResponsePanel({ url }: { url: string }) {
  const [data, setData] = React.useState<JsonValue | undefined>(undefined);

  React.useEffect(() => {
    fetch(url)
      .then((res) => res.json())
      .then((json: JsonValue) => setData(json));
  }, [url]);

  if (data === undefined) return <p className="text-sm text-neutral-500">載入中…</p>;

  return <JsonTreeViewer data={data} rootName="response" />;
}

大型資料預設收合並限制高度

資料層級很深時,把 defaultExpandDepth 設成 1 只展開第一層;外層用 className 限制高度並加上捲軸。

<JsonTreeViewer
  data={orderPayload}
  defaultExpandDepth={1}
  rootName="order"
  className="max-h-96 overflow-auto rounded-lg border p-3"
/>

在 Server Component 頁面直接傳入

JsonValue 只包含可序列化的型別,伺服器端取得的資料可以直接當 props 傳給這個 Client Component。

// app/admin/webhooks/[id]/page.tsx
import { JsonTreeViewer } from "@/components/ui/json-tree-viewer";
import { getWebhookEvent } from "@/lib/webhooks";

export default async function WebhookEventPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const event = await getWebhookEvent(id);

  return (
    <section className="space-y-3">
      <h1 className="text-lg font-semibold">事件 {id}</h1>
      <JsonTreeViewer data={event.payload} rootName="payload" defaultExpandDepth={Infinity} />
    </section>
  );
}

Props

Prop型別預設值說明
dataJsonValue—要渲染的 JSON 資料(物件、陣列或任何原始值)
defaultExpandDepthnumber2預設展開的層數,0 全部收合、Infinity 全部展開
rootNamestring"$"複製路徑時的根名稱,例如 $ 或 data
classNamestring—透傳到最外層容器,與內建樣式合併

可及性

  • 展開/收合為原生 button,附 aria-expanded 與含節點路徑的中文 aria-label,鍵盤 Enter 與 Space 皆可操作
  • 「複製路徑/複製值」按鈕在鍵盤聚焦(focus-visible)時同樣會顯現,不依賴滑鼠 hover
  • 複製成功以圖示切換為打勾提供視覺回饋,且按鈕保持可見 1.4 秒
  • 使用者系統開啟「減少動態效果」時,展開收合與箭頭旋轉改為即時切換,不播放高度動畫

常見問題

可以在 Next.js App Router 使用嗎?

可以。元件檔案開頭已有 "use client",在 Server Component 頁面直接 import 並傳入資料即可。剪貼簿與計時器只在使用者點擊複製時才會用到 navigator 與 window,不影響伺服器渲染。

複製出來的路徑是什麼格式?

根節點使用 rootName(預設 $),合法的 JavaScript 識別字用點記法,陣列索引與含中文、連字號等字元的 key 改用中括號,例如 $.items[0]["shipping-address"]。「值」按鈕複製的是縮排 2 格的 JSON.stringify 結果。

改了 defaultExpandDepth 卻沒有反應?

每個節點的展開狀態只在第一次掛載時依 defaultExpandDepth 決定,之後由使用者自行展開收合。需要整棵樹重新套用時,替 JsonTreeViewer 換一個新的 key 讓它重新掛載。

資料很大會不會很慢?

收合中的節點不會渲染子節點,但元件沒有做虛擬捲動,展開的部分都會留在 DOM 中。資料量大時建議把 defaultExpandDepth 設低,並用 className 限制高度。

為什麼複製沒有成功?

元件使用 navigator.clipboard.writeText,瀏覽器只在 HTTPS 或 localhost 等安全環境提供這個 API;寫入失敗時錯誤會被忽略,但打勾圖示仍會顯示。依賴為 motion、lucide-react、clsx 與 tailwind-merge。