Ark UI Logo
Utilities
Json tree view

JSON Tree View

A component that displays JSON data in an interactive, collapsible tree structure.

Loading...

Anatomy

To set up the JSON tree view correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Examples

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

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

export const Basic = () => {
  return (
    <JsonTreeView.Root
      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',
        },
      }}
    >
      <JsonTreeView.Tree arrow={<ChevronRightIcon />} />
    </JsonTreeView.Root>
  )
}

Different Data Types

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

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

const testArray = [1, 2, 3, 4, 5]
Object.defineProperties(testArray, {
  customProperty: { value: 'custom value', enumerable: false, writable: false },
  anotherProperty: { value: 42, enumerable: false, writable: false },
})

export const ArrayData = () => {
  return (
    <JsonTreeView.Root
      data={{
        normalArray: [1, 2, 3],
        arrayWithNonEnumerableProperties: testArray,
        sparseArray: (() => {
          const sparse = []
          sparse[0] = 'first'
          sparse[5] = 'sixth'
          return sparse
        })(),
      }}
    >
      <JsonTreeView.Tree arrow={<ChevronRightIcon />} />
    </JsonTreeView.Root>
  )
}

Functions and Methods

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

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

const data = [
  function sum(a: number, b: number) {
    return a + b
  },
  async (promises: Promise<any>[]) => await Promise.all(promises),
  function* generator(a: number) {
    while (a > 0) {
      yield a - 1
    }
  },
]

export const Functions = () => {
  return (
    <JsonTreeView.Root data={data}>
      <JsonTreeView.Tree arrow={<ChevronRightIcon />} />
    </JsonTreeView.Root>
  )
}

Regular Expressions

Regular expressions are displayed with their pattern and flags:

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

const data = {
  regex: /^[a-z0-9]+/g,
  case_insensitive: /^(?:[a-z0-9]+)foo.*?/i,
}

export const Regex = () => {
  return (
    <JsonTreeView.Root data={data}>
      <JsonTreeView.Tree arrow={<ChevronRightIcon />} />
    </JsonTreeView.Root>
  )
}

Error Objects

Error objects and their stack traces can be visualized:

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

const data = new Error('Error')

export const Errors = () => {
  return (
    <JsonTreeView.Root data={data}>
      <JsonTreeView.Tree arrow={<ChevronRightIcon />} />
    </JsonTreeView.Root>
  )
}

Map and Set Objects

Native JavaScript Map and Set objects are supported:

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

const data = new Map<string, any>([
  ['name', 'ark-ui-json-tree'],
  ['license', 'MIT'],
  ['elements', new Set(['ark-ui', 123, false, true, null, undefined, 456n])],
  [
    'nested',
    new Map<string, any>([
      [
        'taglines',
        new Set([
          { name: 'ark-ui', feature: 'headless components' },
          { name: 'ark-ui', feature: 'framework agnostic' },
          { name: 'ark-ui', feature: 'accessible by default' },
        ]),
      ],
    ]),
  ],
])

export const MapAndSet = () => {
  return (
    <JsonTreeView.Root data={data}>
      <JsonTreeView.Tree arrow={<ChevronRightIcon />} />
    </JsonTreeView.Root>
  )
}

Controlling Expand Level

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

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

export const ExpandLevel = () => {
  return (
    <JsonTreeView.Root
      defaultExpandedDepth={1}
      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',
        },
      }}
    >
      <JsonTreeView.Tree arrow={<ChevronRightIcon />} />
    </JsonTreeView.Root>
  )
}

Custom Value Rendering

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

import { JsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-react'

export const RenderValue = () => {
  return (
    <JsonTreeView.Root
      defaultExpandedDepth={2}
      data={{
        name: 'John Doe',
        age: 30,
        number: Number.NaN,
        email: 'john.doe@example.com',
        address: {
          street: '123 Main St',
          city: 'Anytown',
          state: 'CA',
          zip: '12345',
        },
      }}
    >
      <JsonTreeView.Tree
        arrow={<ChevronRightIcon />}
        renderValue={(node) => {
          if (node.type === 'text' && typeof node.value === 'string' && isEmail(node.value)) {
            return (
              <a href={`mailto:${node.value}`} target="_blank" rel="noreferrer">
                {node.value}
              </a>
            )
          }
        }}
      />
    </JsonTreeView.Root>
  )
}

const isEmail = (value: string) => {
  const strippedValue = value.replace(/^"(.*)"$/, '$1')
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(strippedValue)
}

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={<ChevronRightIcon />} />
</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.

import { JsonTreeView, useJsonTreeView } from '@ark-ui/react/json-tree-view'
import { ChevronRightIcon } from 'lucide-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={<ChevronRightIcon />} />
    </JsonTreeView.RootProvider>
  )
}

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

API Reference

JsonTreeViewRoot

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
checkedValue
string[]

The controlled checked node value

classNames
JsonTreeViewClassNames

The CSS class names for each part of the component.

collapseStringsAfterLength
number

data
{}

The data to display in the tree.

defaultCheckedValue
string[]

The initial checked node value when rendered. Use when you don't need to control the checked node value.

defaultExpandedDepth
number

The default expand level.

defaultExpandedValue
string[]

The initial expanded node ids when rendered. Use when you don't need to control the expanded node value.

defaultFocusedValue
string

The initial focused node value when rendered. Use when you don't need to control the focused node value.

defaultSelectedValue
string[]

The initial selected node value when rendered. Use when you don't need to control the selected node value.

expandedValue
string[]

The controlled expanded node ids

expandOnClicktrue
boolean

Whether clicking on a branch should open it or not

focusedValue
string

The value of the focused node

groupArraysAfterLength
number

ids
Partial<{ root: string; tree: string; label: string; node: (value: string) => string }>

The ids of the tree elements. Useful for composition.

lazyMountfalse
boolean

Whether to enable lazy mounting

loadChildren
(details: LoadChildrenDetails<JsonNode<any>>) => Promise<JsonNode<any>[]>

Function to load children for a node asynchronously. When provided, branches will wait for this promise to resolve before expanding.

maxPreviewItems
number

onCheckedChange
(details: CheckedChangeDetails) => void

Called when the checked value changes

onExpandedChange
(details: ExpandedChangeDetails<JsonNode<any>>) => void

Called when the tree is opened or closed

onFocusChange
(details: FocusChangeDetails<JsonNode<any>>) => void

Called when the focused node changes

onLoadChildrenComplete
(details: LoadChildrenCompleteDetails<JsonNode<any>>) => void

Called when a node finishes loading children

onLoadChildrenError
(details: LoadChildrenErrorDetails<JsonNode<any>>) => void

Called when loading children fails for one or more nodes

onSelectionChange
(details: SelectionChangeDetails<JsonNode<any>>) => void

Called when the selection changes

quotesOnKeys
boolean

Whether to show quotes on the keys.

selectedValue
string[]

The controlled selected node value

selectionMode'single'
'multiple' | 'single'

Whether the tree supports multiple selection - "single": only one node can be selected - "multiple": multiple nodes can be selected

showNonenumerable
boolean

typeaheadtrue
boolean

Whether the tree supports typeahead search

unmountOnExitfalse
boolean

Whether to unmount on exit.

JsonTreeViewRootProvider

PropDefaultType
value
UseTreeViewReturn<JsonNode<any>>

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
lazyMountfalse
boolean

Whether to enable lazy mounting

unmountOnExitfalse
boolean

Whether to unmount on exit.

JsonTreeViewTree

PropDefaultType
arrow
ReactElement<unknown, string | JSXElementConstructor<any>>

The icon to use for the arrow.

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
indentGuide
boolean | ReactElement<unknown, string | JSXElementConstructor<any>>

The indent guide to use for the tree.

renderValue
(node: JsonNodeHastElement) => ReactNode

The 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
Tab
Moves focus to the tree view, placing the first tree view item in focus.
EnterSpace
Selects the item or branch node
ArrowDown
Moves focus to the next node
ArrowUp
Moves focus to the previous node
ArrowRight
When 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.
ArrowLeft
When 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.
Home
Moves focus to first node without opening or closing a node.
End
Moves focus to the last node that can be focused without expanding any nodes that are closed.
a-zA-Z
Focus 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 + ArrowDown
Moves focus to and toggles the selection state of the next node.
Shift + ArrowUp
Moves focus to and toggles the selection state of the previous node.
Ctrl + A
Selects all nodes in the tree. If all nodes are selected, unselects all nodes.