JSON viewer

A collapsible JSON tree with search, paging for long arrays, and copy value or path.

pnpm dlx shadcn@latest add @uiarc/json-viewer
Live · keyboard ready
GET/v1/orders/ord_8Kd2Q720084 ms
order13 keys
id"ord_8Kd2Q7"
object"order"
status"fulfilled"
livemodefalse
created1757851200
currency"usd"
amount_total48600
discountnull
orderobject, 13 keys
  • Inspecting a JSON payload in a developer dashboard, such as webhooks or API logs.
  • Large nested objects where search and copy path save time.
  • Arrays with hundreds of items, which load in pages of pageSize.
  • Use code-block to show JSON as formatted source for copying whole.
  • Use tree-view for folders, navigation, or other non-JSON hierarchies.
  • Use data-grid when the data is a flat list of records.

Installation

Add JSON viewer with the shadcn CLI, or copy the source by hand.

pnpm dlx shadcn@latest add @uiarc/json-viewer

Adds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { JsonViewer } from "@/components/arc/json-viewer/json-viewer"; export function WebhookPayload({ payload }: { payload: unknown }) {  return (    <JsonViewer      data={payload}      rootName="event"      defaultExpandDepth={2}      maxHeight={360}      onCopy={({ kind }) => toast(kind === "path" ? "Path copied" : "Value copied")}    />  );}

JsonViewer

A collapsible JSON tree with type colors, search that opens matching branches, paged long branches, and copy value or path per row.

PropTypeDefaultDescription
dataRequiredunknown–Any JSON-like value.
rootNamestring"root"Name of the root in paths, as in root.users[0].name.
defaultExpandDepthnumber1Levels open on first render when defaultExpanded is not set. 1 opens the root.
expandedstring[]–Controlled paths of open branches.
defaultExpandedstring[]–Open branch paths on first render when uncontrolled.
onExpandedChange(paths: string[]) => void–Called when branches open or close.
searchablebooleantrueShows the search field.
querystring–Controlled search text.
defaultQuerystring""Starting search text when uncontrolled.
onQueryChange(query: string) => void–Called as the search text changes.
pageSizenumber50Children shown per page in a long array or object.
copyablebooleantrueShows copy value and copy path actions.
onCopy(detail: JsonViewerCopyDetail) => void–Called after a copy with { kind: "value" | "path", path, text }.
onSelect(detail: { path: string; value: unknown; type: JsonValueType }) => void–Called when a row becomes the current one.
showPathbooleantrueShows the current row's path under the tree.
maxHeightnumber | string420Height of the scrolling tree area. Numbers are pixels.
labelstring"JSON"Accessible name of the tree.
classNamestring–Class on the root.
refRef<HTMLDivElement>–The root element.
ArrowDownorArrowUp
Moves to the next or previous visible row.
ArrowRight
Opens a closed branch, or moves into an open one.
ArrowLeft
Closes an open branch, or moves to the parent.
HomeorEnd
Jumps to the first or last visible row.
EnterorSpace
Toggles a branch, or loads the next page on a Show more row.
Cmd/Ctrl+C
Copies the focused row's value; add Shift to copy its path. Ignored while text is selected.
/
Focuses the search field.
EnterorShift+Enter (in search)
Jumps to the next or previous match.
Escape (in search)
Clears the query.
ArrowDown (in search)
Moves focus into the tree.
  • Follows the WAI-ARIA tree pattern: role="tree" with treeitems carrying aria-level, aria-posinset, aria-setsize, aria-expanded, and aria-selected.
  • One row is tabbable at a time; each row's label reads its key and value, or its type and item count.
  • The match counter is aria-live polite, and a status region announces copies and failures.
  • Row copy buttons are out of the tab order; use Cmd or Ctrl with C, or the path bar's copy button, from the keyboard.
  • Each row unfolds its own height, so opening a branch, loading a page, or expanding all share one motion.
  • The current-row highlight glides between rows with a shared layout id, and the tree scroll springs to where the row will sit once rows settle.
  • Copy glyphs swap to a check or cross with a small scale and blur.
  • Reduced motion, or more than 400 visible rows, makes row changes instant; reduced motion also jumps the scroll and highlight.
  • The tree scrolls inside maxHeight; long keys and values truncate with an ellipsis and strings over 40 characters show in full on hover.
  • At 420px viewport width and below the indent drops from 16px to 12px, keys cap at 40% of the row, and the path type hides.
  • Row copy actions show on hover with a fine pointer; on touch they show on the current row.
  • Rows are a flat list rebuilt only when data, open branches, pages, or search change; nothing is virtualized, so paging keeps the DOM small.
  • Above 400 visible rows the height animations switch off to keep expand all fast.
  • Search walks the whole value on each keystroke; for multi-megabyte payloads control query and debounce it.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Use for API responses, webhook payloads, logs, and config inspection in developer tools.
  • Search matches keys and primitive values case-insensitively, opens the branches that hold them, and stops at 2000 matches.
  • Control expanded to persist open branches across reloads, or to open a path from elsewhere in the page.
  • For formatted source code use code-block; for tabular data use data-grid.

The full library index for assistants is at /llms.txt.