Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Data Display

JSON Viewer

Data Display

JSON Viewer React component for Tailwind CSS v4

GanttKbd
Live props
Content
rootName
locale
State
defaultExpandDepth1
loading
skeletonCount8
Behavior
searchable
searchIn
pathFormat
rootPathName
fileName
downloadable
copyable
rowActions
Layout
toolbar
heightAuto
maxHeight480px
Appearance
maxStringLength120
showCounts
showTypes
showLineNumbers
quoteKeys
sortKeys
detectDates
size
Props
virtualThreshold300
wrap
Code
import { JsonViewer } from "@/components/ui/json-viewer"

<JsonViewer />
  1. Home
  2. Components
  3. Data Display
  4. JSON Viewer
Pro

JSON Viewer React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A collapsible JSON tree with type colors, search that opens the matching branches, copy value or path, and virtualization for huge payloads.

Click or tap a branch to open or close it: the chevron turns and small branches slide open. Collapsed objects show their first keys and arrays their first values, with a count. Type in the search box (or press Ctrl+F / ⌘F while inside the viewer) and every key or value that matches is highlighted, its branches open and the first hit scrolls to the middle; Enter and Shift+Enter or the arrows step through the hits and the counter reads 2 of 5. Escape clears the search, a second Escape returns to the tree. With a mouse, hovering a row shows Copy value and Copy path; on a phone a long press opens a sheet that repeats the value (and a date in local time) with the same actions plus Expand all from here. The toolbar expands or collapses everything, copies the whole JSON and downloads it as a dated .json file; below 512px of width it folds into a ⋯ menu. The tree is one Tab stop: Up and Down move, Right opens or steps into a branch, Left closes it or goes to the parent, Home and End jump, * opens every sibling, Enter toggles a branch or selects a value, c copies the value and Shift+C its path, and the context menu key opens the row's actions. Long strings stop at maxStringLength with a Show more button (Right and Left on the row show and hide the rest), arrays over 100 items open in pages of 100, and above 300 visible rows only what is on screen is rendered.

JSON Viewer is a Pro React component in the React data display components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add json-viewer, together with Action Sheet, Button, Empty State, Search Input, Tooltip and 10 more and the npm packages @tanstack/react-virtual, motion and lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add json-viewer

JSON Viewer is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import JsonViewer from @/components/ui/json-viewer.

import { JsonViewer, type JsonViewerLabels } from "@/components/ui/json-viewer"

const labels: Partial<JsonViewerLabels> = {
  search: "Search keys and values",
  noMatches: "Nothing found",
}

const webhook = {
  id: "evt_4912873366",
  account: "acct_12345674",
  created_at: "2026-09-24T16:38:12-04:00",
  status: "ok",
  invoice: { number: "2026-0412", customer: { name: "Acme Corp", tax_id: "12-3456740" } },
  warnings: [],
}

export function WebhookDetails() {
  return (
    <JsonViewer
      data={webhook}
      rootName="webhook"
      defaultExpandDepth={2}
      fileName="invoice-2026-0412"
      locale="en-US"
      labels={labels}
      onSelect={(path, value) => console.log(path, value)}
    />
  )
}

Props

  • data*
    unknown

    Any JSON-compatible value. Dates, undefined, BigInt (123n), NaN and Infinity show as words or numbers, Maps and Sets as objects and arrays, circular references as [Circular → data.parent]. Strings that contain JSON are not parsed: pass the parsed value. undefined shows the empty state.

  • rootNamedefault ""
    string | false

    A key label on the root, like "payload". Empty (false) shows the root braces only.

  • defaultExpandDepthdefault 1
    number

    Levels open on mount: 0 keeps the root closed, 1 shows its keys. Deeper opening goes through the API (expandToDepth).

  • expandedKeys
    string[]

    Controlled open branches as pathKey strings ("$", "$/invoice/lines", pages of long arrays as "$/items/~g100").

  • defaultExpandedKeys
    string[]

    Open branches on mount; replaces defaultExpandDepth when set.

  • onExpandedKeysChange
    (keys: string[]) => void

    Every open or close, including the branches a search opens.

  • searchabledefault true
    boolean

    The search box in the toolbar. Without it the toolbar shows the root name and its count.

  • searchIndefault "both"
    "keys" | "values" | "both"

    What the search matches. Values match as their text (numbers, true, null too); case and diacritics are ignored.

  • toolbardefault true
    boolean

    The row with search, expand / collapse all, copy and download.

  • pathFormatdefault "js"
    "js" | "pointer"

    Copy path as data.items[0].name (keys with spaces as ["full name"]) or as a JSON Pointer /items/0/name.

  • rootPathNamedefault "data"
    string

    The root identifier in js paths: data.invoice.customer.

  • maxStringLengthdefault 120
    number

    Longer strings stop with an ellipsis and a Show more button. A search hit further in shows the whole string.

  • showCountsdefault true
    boolean

    3 keys / 12 items after objects and arrays.

  • showTypesdefault false
    boolean

    A small type chip before each value: string, int, float, bool, null, date, object, array.

  • showLineNumbersdefault false
    boolean

    A sticky gutter with row numbers that stays put while long lines scroll sideways.

  • quoteKeysdefault true
    boolean

    "name": like JSON, or name: without quotes.

  • sortKeysdefault false
    boolean

    Shows object keys alphabetically. Display only: copy and download keep the original order.

  • detectDatesdefault true
    boolean

    ISO date strings get the date color (still quoted) and a native tooltip with the local date and time.

  • sizedefault "md"
    "sm" | "md"

    12px text on 24px rows or 13px on 28px rows. Rows grow to 36px on touch screens.

  • heightdefault 0
    number

    A fixed body height in px. 0 grows with the content up to maxHeight.

  • maxHeightdefault 480
    number

    The tallest the body grows when height is 0; it scrolls inside after that.

  • virtualThresholddefault 300
    number

    Visible rows above which only the rows on screen are rendered (each row measured, 12 rows of overscan).

  • wrapdefault "auto"
    "auto" | boolean

    Long values break onto more lines, indented under their key, instead of scrolling sideways. auto wraps below 512px of the viewer's width (phones).

  • onSelect
    (path: JsonPath, value: unknown) => void

    A value activated with Enter, a click or a tap. With it set, the selected row stays highlighted.

  • fileNamedefault "data"
    string

    Download name base; the file is saved as data-2026-09-24-1640.json.

  • downloadabledefault true
    boolean

    The Download action in the toolbar.

  • copyabledefault true
    boolean

    The Copy JSON action in the toolbar (indented, circular references and BigInts made safe).

  • rowActionsdefault true
    boolean

    Copy value and Copy path on each row: on hover or focus with a mouse, on long press on touch screens.

  • loadingdefault false
    boolean

    Skeleton rows in place of the tree; the toolbar actions wait.

  • skeletonCountdefault 8
    number

    Skeleton rows while loading.

  • emptyState
    ReactNode

    Replaces the built-in No data state shown when data is undefined.

  • setApi
    (api: JsonViewerApi) => void

    Called after mount (and when the API changes) with { expandAll, collapseAll, expandToDepth(depth), expandPath(path), scrollToPath(path), search(query) }.

  • localedefault ""
    string

    Counts and date tooltips. Empty uses the UIProvider locale, then the browser's.

  • labels
    Partial<JsonViewerLabels>

    Every string: search, matches(i, n), noMatches, previousMatch, nextMatch, expandAll, collapseAll, copy, copyValue, copyPath, download, copied, copyFailed, downloaded(name), items(count, formatted), keys(count, formatted), more(count, formatted), less, expand, collapse, expandHere, moreActions, cancel, circular, empty, loading, tree. English defaults in DEFAULT_JSON_VIEWER_LABELS.

  • classNames
    Partial<Record<"toolbar" | "summary" | "search" | "body" | "row" | "lineNumber" | "toggle" | "key" | "value" | "type" | "preview" | "count" | "actions" | "more" | "empty", string>>

    Extra classes for the inner parts.

  • className
    string

    Extra classes for the root panel, merged last. Give it a height (h-full) and height={0} with maxHeight={0} to fill a pane.

Parts

  • formatJsonPath

    function

    The path text copy path uses: formatJsonPath(["items", 0, "name"]) is data.items[0].name, with "pointer" /items/0/name. Signature: (path: JsonPath, format?: "js" | "pointer", rootName?: string) => string.

  • pathKey

    function

    The key expandedKeys uses for a path: pathKey(["invoice", "lines"]) is "$/invoice/lines". Signature: (path: JsonPath) => string.

  • flattenJson

    function

    The visible rows (nodes, array pages and closing braces) for a set of open keys, for tests and custom renderers. Signature: (value: unknown, expandedKeys: Iterable<string>, options?: { rootName?; sortKeys?; detectDates? }) => JsonRow[].

  • JSON_COLORS

    constant

    The value color classes, shared with anything that prints JSON inline (log metadata). Type: Record<"key" | "string" | "number" | "boolean" | "null" | "date" | "punctuation", string>.

  • jsonTypeOf

    function

    The node type the viewer colors a value by: object, array (Sets too), string, number, boolean, null, undefined, or date for Date objects and ISO date strings. Signature: (value: unknown, detectDates = true) => JsonNodeType.

  • DEFAULT_JSON_VIEWER_LABELS

    constant

    Every English string the viewer prints or announces (search, match counts, copy and download feedback, item counts, menu entries). Spread it and override what you translate.

  • JsonPath

    type

    A path into the data as keys and indexes, e.g. ["items", 0, "name"]. onSelect and the copy actions use it.

  • JsonViewerLabels

    type

    The shape of labels; plain strings plus functions for counts like items(count, formatted).

Examples

Search

Hits in keys and values light up, their branches open and the counter reads 1 of 2.

10,000 rows, virtualized

Long arrays open in pages of 100 and only the visible rows are in the DOM.

Select a value

onSelect with JSON Pointer paths feeding a side panel.

Tool call input

size sm with type chips and line numbers inside an AI tool call card.

Long strings

A base64 PDF truncated at 120 characters with a show more button.

On a phone

Long press a row for an action sheet; the toolbar folds into a menu.

Loading and empty

Skeleton rows while the payload loads, and the empty state without data.

Dependencies

@tanstack/react-virtualmotionlucide-reactaction-sheetbuttonempty-statesearch-inputtooltipuse-clipboarduse-controllable-stateuse-localeuse-long-pressuse-media-queryfile-exportmotionnumber-formattext-matchui-config

Files

  • components/ui/json-viewer.tsx

FAQ

Is the React JSON Viewer component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install JSON Viewer?

Run npx wingo-ui@latest add json-viewer. It also adds the Wingo UI items it builds on (Action Sheet, Button, Empty State, Search Input, Tooltip and 10 more) and the npm packages @tanstack/react-virtual, motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/json-viewer.

How does JSON Viewer behave on phones?

With a mouse, hovering a row shows Copy value and Copy path; on a phone a long press opens a sheet that repeats the value (and a date in local time) with the same actions plus Expand all from here.

See also

Tree ViewCode BlockCopy ButtonSearch InputFile exportlib

Used in

Schema BuilderLog Viewer

More React data display components

MarkdownPresenceSchedulerTagTimelineKbd
All 23 React data display components

Articles using this component

  • React Diff Viewer in React 19: Split, Unified, Word Diffs

    Component guides · Oct 16, 2026 · 9 min read

  • React JSON Viewer: Search, Copy Paths and Big Payloads

    Component guides · Oct 16, 2026 · 9 min read

PreviousGanttNext Kbd
{9 keys
"id": "evt_4912873366",
"request_id": "req_5003284511",
"account": "acct_12345674",
"type": "invoice.paid",
"created_at": "2026-09-24T16:38:12-04:00",
"status": "ok",
"message": "Invoice in_5003284511 issued by acct_56781233 to acct_12345674 was paid in full and can be downloaded from the dashboard…",
"invoice": { number, issued_on, due_on, currency, … },10 keys
"warnings": []
}

selected: data.invoice.customer.name · search in: both · file: data-2026-09-24-1640.json · locale: auto