DocsBlog

Get Started

Components

Data Grid

Signals

Styling

Theming

↑↓Navigate
↵Select
EscClose
  • 1.8.0

  • Day

    Night

    Preview

    Switch mode
  • cerberus

    acheron

    elysium

    oceanus

Get Started
Components
Data Grid
Signals
Styling
Theming

Concepts

OverviewCompositionCerberus ContextTesting

Layout

Aspect RatioBleedBoxCenterContainerContainer QueryDividerFlexFloatGridGroupLink OverlayScrollableStackWrap

Components

AccordionAdmonitionAvatarButtonCarouselCheckboxClipboardCollapsibleComboboxConfirm ModalCTA ModalDate PickerDialogFieldFieldsetFile UploaderIconButtonInputLoading StatesMarqueeMenuNotificationsNumber InputPaginationPin InputPopoverProgress IndicatorsPrompt ModalRadioRatingSelectSliderSplit ButtonSwitchTableTabsTagTextTextareaToggleTooltip

Utilities

Client OnlyDownload TriggerEnvironmentFeature FlagsFocus TrapForFormat ByteFormat NumberFormat Relative TimeFormat Relative TimeFrameHighlightJSON Tree ViewLocalePortalPresenceShowSwapsplitPropsTheme

JSON Tree View

A component that displays a JSON object in a tree-like structure.

  • npm
View as Markdown
Open this page in Markdown
Anthropic
Open in Claude
Ask questions about this page
OpenAI
Open in ChatGPT
Ask questions about this page

Examples

Learn how to use the JsonTreeView component in your project. Let's take a look at the most basic example:

Loading example...

Different Data Types

The JSON tree view can display various JavaScript data types including objects, arrays, primitives, and special values:

Loading example...

Functions and Methods

Display JavaScript functions, async functions, and generators in your JSON tree:

Loading example...

Regular Expressions

Regular expressions are displayed with their pattern and flags:

Loading example...

Error Objects

Error objects and their stack traces can be visualized:

Loading example...

Map and Set Objects

Native JavaScript Map and Set objects are supported:

Loading example...

Controlling Expand Level

Use the defaultExpandedDepth prop to control how many levels are expanded by default:

Loading example...

Custom Value Rendering

You can customize how specific values are rendered using the renderValue prop. This example shows how to make email addresses clickable:

Loading example...

Configuration Options

The JSON tree view supports several configuration options to customize the display:

<JsonTreeView.Root
  data={data}
  defaultExpandedDepth={2}
  quotesOnKeys={true}
  showNonenumerable={true}
  maxPreviewItems={5}
  collapseStringsAfterLength={50}
  groupArraysAfterLength={100}
>
  <JsonTreeView.Tree arrow={<ChevronRight />} />
</JsonTreeView.Root>

Configuration Options:

  • quotesOnKeys: Whether to show quotes around object keys
  • showNonenumerable: Whether to show non-enumerable properties
  • maxPreviewItems: Maximum number of items to show in object/array previews
  • collapseStringsAfterLength: Collapse strings longer than this length
  • groupArraysAfterLength: Group array items when array is longer than this length

Using the Root Provider

The RootProvider component provides a context for the JSON tree view. It accepts the value of the useJsonTreeView hook. You can leverage it to access the component state and methods from outside the JSON tree view.

'use client'
 
import { JsonTreeView, useJsonTreeView } from '@cerberus/react'
import { ChevronRight } from '@carbon/icons-react'
 
export const RootProvider = () => {
  const jsonTreeView = useJsonTreeView({
    data: {
      name: 'John Doe',
      age: 30,
      email: 'john.doe@example.com',
      tags: ['tag1', 'tag2', 'tag3'],
      address: {
        street: '123 Main St',
        city: 'Anytown',
        state: 'CA',
        zip: '12345',
      },
    },
  })
 
  return (
    <JsonTreeView.RootProvider value={jsonTreeView}>
      <JsonTreeView.Tree arrow={<ChevronRight />} />
    </JsonTreeView.RootProvider>
  )
}

If you're using the RootProvider component, you don't need to use the Root component.

API Reference

Root

Props

PropTypeRequiredDefaultDescription
asChildbooleanfalseundefinedUse the provided child element as the default rendered element, combining their props and behavior.
canRename(node: JsonNode<any>, indexPath: IndexPath) => booleanfalseundefinedFunction to determine if a node can be renamed
checkedValuestring[]falseundefinedThe controlled checked node value
collapseStringsAfterLengthnumberfalseundefinedundefined
data{}falseundefinedThe data to display in the tree.
defaultCheckedValuestring[]falseundefinedThe initial checked node value when rendered.
Use when you don't need to control the checked node value.
defaultExpandedDepthnumberfalseundefinedThe default expand level.
defaultExpandedValuestring[]falseundefinedThe initial expanded node ids when rendered.
Use when you don't need to control the expanded node value.
defaultFocusedValuestringfalseundefinedThe initial focused node value when rendered.
Use when you don't need to control the focused node value.
defaultSelectedValuestring[]falseundefinedThe initial selected node value when rendered.
Use when you don't need to control the selected node value.
expandedValuestring[]falseundefinedThe controlled expanded node ids
expandOnClickbooleanfalsetrueWhether clicking on a branch should open it or not
focusedValuestringfalseundefinedThe value of the focused node
groupArraysAfterLengthnumberfalseundefinedundefined
hideModeHideModefalse'display-none'How to hide content when mounted but not present.
- 'display-none': HTML hidden attribute. Effects stay alive.
- 'activity': React 19 <Activity mode="hidden">. Effects pause. Requires React 19+.
idsPartial<{ root: string; tree: string; label: string; node: (value: string) => string }>falseundefinedThe ids of the tree elements. Useful for composition.
lazyMountbooleanfalsefalseWhether to enable lazy mounting
loadChildren(details: LoadChildrenDetails<JsonNode<any>>) => Promise<JsonNode<any>[]>falseundefinedFunction to load children for a node asynchronously.
When provided, branches will wait for this promise to resolve before expanding.
maxPreviewItemsnumberfalseundefinedundefined
onBeforeRename(details: RenameCompleteDetails) => booleanfalseundefinedCalled before a rename is completed. Return false to prevent the rename.
onCheckedChange(details: CheckedChangeDetails) => voidfalseundefinedCalled when the checked value changes
onExpandedChange(details: ExpandedChangeDetails<JsonNode<any>>) => voidfalseundefinedCalled when the tree is opened or closed
onFocusChange(details: FocusChangeDetails<JsonNode<any>>) => voidfalseundefinedCalled when the focused node changes
onLoadChildrenComplete(details: LoadChildrenCompleteDetails<JsonNode<any>>) => voidfalseundefinedCalled when a node finishes loading children
onLoadChildrenError(details: LoadChildrenErrorDetails<JsonNode<any>>) => voidfalseundefinedCalled when loading children fails for one or more nodes
onRenameComplete(details: RenameCompleteDetails) => voidfalseundefinedCalled when a node label rename is completed
onRenameStart(details: RenameStartDetails<JsonNode<any>>) => voidfalseundefinedCalled when a node starts being renamed
onSelectionChange(details: SelectionChangeDetails<JsonNode<any>>) => voidfalseundefinedCalled when the selection changes
quotesOnKeysbooleanfalseundefinedWhether to show quotes on the keys.
scrollToIndexFn(details: ScrollToIndexDetails<JsonNode<any>>) => voidfalseundefinedFunction to scroll to a specific index.
Useful for virtualized tree views.
selectedValuestring[]falseundefinedThe controlled selected node value
selectionMode'single' | 'multiple'false"single"Whether the tree supports multiple selection
- "single": only one node can be selected
- "multiple": multiple nodes can be selected
showNonenumerablebooleanfalseundefinedundefined
translationsIntlTranslationsfalseundefinedSpecifies the localized strings that identifies the accessibility elements and their states
typeaheadbooleanfalsetrueWhether the tree supports typeahead search
unmountOnExitbooleanfalsefalseWhether to unmount on exit.

JsonTreeViewRootProvider

Props

PropTypeRequiredDefaultDescription
valueUseJsonTreeViewReturntrueundefinedundefined
asChildbooleanfalseundefinedUse the provided child element as the default rendered element, combining their props and behavior.
hideModeHideModefalse'display-none'How to hide content when mounted but not present.
- 'display-none': HTML hidden attribute. Effects stay alive.
- 'activity': React 19 <Activity mode="hidden">. Effects pause. Requires React 19+.
lazyMountbooleanfalsefalseWhether to enable lazy mounting
unmountOnExitbooleanfalsefalseWhether to unmount on exit.

JsonTreeViewTree

Props

PropTypeRequiredDefaultDescription
arrowReactElement<unknown, string | JSXElementConstructor<any>>falseundefinedThe icon to use for the arrow.
asChildbooleanfalseundefinedUse the provided child element as the default rendered element, combining their props and behavior.
indentGuideboolean | ReactElement<unknown, string | JSXElementConstructor<any>>falseundefinedThe indent guide to use for the tree.
renderValue(node: JsonNodeHastElement) => ReactNodefalseundefinedThe function to render the value of the node.

Accessibility

The JSON tree view is built on top of the Tree View component and complies with the Tree View WAI-ARIA design pattern.

Keyboard Support

KeyDescription
TabMoves focus to the tree view, placing the first tree view item in focus.
Enter + SpaceSelects the item or branch node
ArrowDownMoves focus to the next node
ArrowUpMoves focus to the previous node
ArrowRightWhen focus is on a closed branch node, opens the branch.
When focus is on an open branch node, moves focus to the first item node.
ArrowLeftWhen focus is on an open branch node, closes the node.
When focus is on an item or branch node, moves focus to its parent branch node.
HomeMoves focus to first node without opening or closing a node.
EndMoves focus to the last node that can be focused without expanding any nodes that are closed.
a-z + A-ZFocus moves to the next node with a name that starts with the typed character. The search logic ignores nodes that are descendants of closed branch.
*Expands all sibling nodes that are at the same depth as the focused node.
Shift + ArrowDownMoves focus to and toggles the selection state of the next node.
Shift + ArrowUpMoves focus to and toggles the selection state of the previous node.
Ctrl + ASelects all nodes in the tree. If all nodes are selected, unselects all nodes.

On this page

  • Examples
    • Different Data Types
    • Functions and Methods
    • Regular Expressions
    • Error Objects
    • Map and Set Objects
    • Controlling Expand Level
    • Custom Value Rendering
    • Configuration Options
    • Using the Root Provider
  • API Reference
    • Root
      • Props
    • JsonTreeViewRootProvider
      • Props
    • JsonTreeViewTree
      • Props
  • Accessibility
    • Keyboard Support
Edit this page on Github
{ name: "John Doe", age: 30, email: "john.doe@example.com", … }
name: "John Doe"
age: 30
email: "john.doe@example.com"
tags: (3) [ "tag1", "tag2", "tag3" ]
0: "tag1"
1: "tag2"
2: "tag3"
length: 3
address: { street: "123 Main St", city: "Anytown", state: "CA", … }
street: "123 Main St"
city: "Anytown"
state: "CA"
zip: "12345"
{ normalArray: Array(3), arrayWithNonEnumerableProperties: Array(5), sparseArray: Array(6) }
normalArray: (3) [ 1, 2, 3 ]
0: 1
1: 2
2: 3
length: 3
arrayWithNonEnumerableProperties: (5) [ 1, 2, 3, … ]
0: 1
1: 2
2: 3
3: 4
4: 5
length: 5
customProperty: "custom value"
anotherProperty: 42
sparseArray: (6) [ "first", "sixth" ]
0: "first"
5: "sixth"
length: 6
(3) [ ƒ(…), ƒ(…), ƒ(…) ]
0: ƒ (a,b)
name: "anonymous"
length: 2
constructor: "Function"
[[Function]]: "function(a,b){return a+b}"
1: async ƒ a=>await Promise.all(a)
name: "anonymous"
length: 1
constructor: "AsyncFunction"
[[Function]]: "async a=>await Promise.all(a)"
2: ƒ* (a)
name: "anonymous"
length: 1
constructor: "GeneratorFunction"
[[Function]]: "function*(a){for(;a>0;)yield a-1}"
length: 3
{ regex: /^[a-z0-9]+/g, case_insensitive: /^(?:[a-z0-9]+)foo.*?/i }
regex: /^[a-z0-9]+/g
lastIndex: 0
dotAll: false
flags: "g"
global: true
hasIndices: false
ignoreCase: false
multiline: false
source: "^[a-z0-9]+"
sticky: false
unicode: false
case_insensitive: /^(?:[a-z0-9]+)foo.*?/i
lastIndex: 0
dotAll: false
flags: "i"
global: false
hasIndices: false
ignoreCase: true
multiline: false
source: "^(?:[a-z0-9]+)foo.*?"
sticky: false
unicode: false
Error: Error
name: "Error"
message: "Error"
stack: Error: Error\n + at module evaluation (/vercel/path0/docs/.next/server/chunks/ssr/_0s2-f88._.js:5:4199)\n + at instantiateModule (/vercel/path0/docs/.next/server/chunks/ssr/[turbopack]_runtime.js:889:9)\n + at getOrInstantiateModuleFromParent (/vercel/path0/docs/.next/server/chunks/ssr/[turbopack]_runtime.js:913:12)\n + at Context.commonJsRequire [as r] (/vercel/path0/docs/.next/server/chunks/ssr/[turbopack]_runtime.js:373:12)\n + at globalThis.__next_require__ (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:138:27800)\n + at f (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:154403)\n + at X (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:165536)\n + at I (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:162669)\n + at rZ (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:66888)\n + at ah (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:107136)\n + at af (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:106940)\n + at aS (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:114685)\n + at ac (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:100379)\n + at ah (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:109623)\n + at af (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:106940)\n + at aS (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:114685)\n + at ap (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:111684)\n + at ah (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:109897)\n + at af (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:106940)\n + at aS (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:114685)\n + at ac (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:100379)\n + at ah (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:109623)\n + at af (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:106940)\n + at ah (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:109858)\n + at aO (/vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:121681)\n + at /vercel/path0/node_modules/.pnpm/next@16.3.4_@babel+core@7.29.7_supports-color@7.2.0__@opentelemetry+api@1.9.0_@types+no_3bcdcc3208286da0d703adfbcef3a68f/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:2:80398\n + at node:internal/process/task_queues:151:7\n + at AsyncResource.runInAsyncScope (node:async_hooks:227:14)\n + at AsyncResource.runMicrotask (node:internal/process/task_queues:148:8)\n + at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
Map(4) { "name" => "ark-ui-json-tree", "license" => "MIT", "elements" => Set(6), … }
[[Entries]]: (4) [ {…}, {…}, {…}, … ]
0: { key: "name", value: "ark-ui-json-tree" }
key: "name"
value: "ark-ui-json-tree"
1: { key: "license", value: "MIT" }
key: "license"
value: "MIT"
2: { key: "elements", value: Set(6) }
key: "elements"
value: Set(6) { "ark-ui", 123, false, … }
[[Entries]]: (6) [ "ark-ui", 123, false, … ]
0: "ark-ui"
1: 123
2: false
3: true
4: null
5: undefined
size: 6
3: { key: "nested", value: Map(1) }
key: "nested"
value: Map(1) { "taglines" => Set(3) }
[[Entries]]: (1) [ {…} ]
0: { key: "taglines", value: Set(3) }
key: "taglines"
value: Set(3) { Object, Object, Object }
[[Entries]]: (3) [ {…}, {…}, {…} ]
0: { name: "ark-ui", feature: "headless components" }
name: "ark-ui"
feature: "headless components"
1: { name: "ark-ui", feature: "framework agnostic" }
name: "ark-ui"
feature: "framework agnostic"
2: { name: "ark-ui", feature: "accessible by default" }
name: "ark-ui"
feature: "accessible by default"
size: 3
size: 1
size: 4
{ name: "John Doe", age: 30, email: "john.doe@example.com", … }
name: "John Doe"
age: 30
email: "john.doe@example.com"
tags: (3) [ "tag1", "tag2", "tag3" ]
0: "tag1"
1: "tag2"
2: "tag3"
length: 3
address: { street: "123 Main St", city: "Anytown", state: "CA", … }
street: "123 Main St"
city: "Anytown"
state: "CA"
zip: "12345"
{ name: "John Doe", age: 30, number: NaN, … }
name: "John Doe"
age: 30
number: NaN
email: "john.doe@example.com"
address: { street: "123 Main St", city: "Anytown", state: "CA", … }
street: "123 Main St"
city: "Anytown"
state: "CA"
zip: "12345"