Components
Tree view

Tree View

A component that is used to show a tree hierarchy.

panda.config.ts
package.json
renovate.json
README.md

Anatomy

To set up the tree view component 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 TreeView component in your project. Let's take a look at the most basic example:

import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view'
import { CheckSquareIcon, ChevronRightIcon, FileIcon, FolderIcon } from 'lucide-solid'
import { For, Show } from 'solid-js'

interface Node {
  id: string
  name: string
  children?: Node[]
}

const collection = createTreeCollection<Node>({
  nodeToValue: (node) => node.id,
  nodeToString: (node) => node.name,
  rootNode: {
    id: 'ROOT',
    name: '',
    children: [
      {
        id: 'node_modules',
        name: 'node_modules',
        children: [
          { id: 'node_modules/zag-js', name: 'zag-js' },
          { id: 'node_modules/pandacss', name: 'panda' },
          {
            id: 'node_modules/@types',
            name: '@types',
            children: [
              { id: 'node_modules/@types/react', name: 'react' },
              { id: 'node_modules/@types/react-dom', name: 'react-dom' },
            ],
          },
        ],
      },
      {
        id: 'src',
        name: 'src',
        children: [
          { id: 'src/app.tsx', name: 'app.tsx' },
          { id: 'src/index.ts', name: 'index.ts' },
        ],
      },
      { id: 'panda.config', name: 'panda.config.ts' },
      { id: 'package.json', name: 'package.json' },
      { id: 'renovate.json', name: 'renovate.json' },
      { id: 'readme.md', name: 'README.md' },
    ],
  },
})

export const Basic = () => {
  return (
    <TreeView.Root collection={collection}>
      <TreeView.Label>Tree</TreeView.Label>
      <TreeView.Tree>
        <For each={collection.rootNode.children}>
          {(node, index) => <TreeNode node={node} indexPath={[index()]} />}
        </For>
      </TreeView.Tree>
    </TreeView.Root>
  )
}

const TreeNode = (props: TreeView.NodeProviderProps<Node>) => {
  const { node, indexPath } = props
  return (
    <TreeView.NodeProvider node={node} indexPath={indexPath}>
      <Show
        when={node.children}
        fallback={
          <TreeView.Item>
            <TreeView.ItemIndicator>
              <CheckSquareIcon />
            </TreeView.ItemIndicator>
            <TreeView.ItemText>
              <FileIcon />
              {node.name}
            </TreeView.ItemText>
          </TreeView.Item>
        }
      >
        <TreeView.Branch>
          <TreeView.BranchControl>
            <TreeView.BranchText>
              <FolderIcon /> {node.name}
            </TreeView.BranchText>
            <TreeView.BranchIndicator>
              <ChevronRightIcon />
            </TreeView.BranchIndicator>
          </TreeView.BranchControl>
          <TreeView.BranchContent>
            <TreeView.BranchIndentGuide />
            <For each={node.children}>
              {(child, index) => <TreeNode node={child} indexPath={[...indexPath, index()]} />}
            </For>
          </TreeView.BranchContent>
        </TreeView.Branch>
      </Show>
    </TreeView.NodeProvider>
  )
}

Using the Root Provider

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

import { TreeView, createTreeCollection, useTreeView } from '@ark-ui/solid/tree-view'
import { CheckSquareIcon, ChevronRightIcon, FileIcon, FolderIcon } from 'lucide-solid'
import { For, Show } from 'solid-js'

interface Node {
  id: string
  name: string
  children?: Node[]
}

const collection = createTreeCollection<Node>({
  nodeToValue: (node) => node.id,
  nodeToString: (node) => node.name,
  rootNode: {
    id: 'ROOT',
    name: '',
    children: [
      {
        id: 'node_modules',
        name: 'node_modules',
        children: [
          { id: 'node_modules/zag-js', name: 'zag-js' },
          { id: 'node_modules/pandacss', name: 'panda' },
          {
            id: 'node_modules/@types',
            name: '@types',
            children: [
              { id: 'node_modules/@types/react', name: 'react' },
              { id: 'node_modules/@types/react-dom', name: 'react-dom' },
            ],
          },
        ],
      },
      {
        id: 'src',
        name: 'src',
        children: [
          { id: 'src/app.tsx', name: 'app.tsx' },
          { id: 'src/index.ts', name: 'index.ts' },
        ],
      },
      { id: 'panda.config', name: 'panda.config.ts' },
      { id: 'package.json', name: 'package.json' },
      { id: 'renovate.json', name: 'renovate.json' },
      { id: 'readme.md', name: 'README.md' },
    ],
  },
})

export const RootProvider = () => {
  const treeView = useTreeView({ collection })

  return (
    <TreeView.RootProvider value={treeView}>
      <TreeView.Label>Tree</TreeView.Label>
      <TreeView.Tree>
        <For each={collection.rootNode.children}>
          {(node, index) => <TreeNode node={node} indexPath={[index()]} />}
        </For>
      </TreeView.Tree>
    </TreeView.RootProvider>
  )
}

const TreeNode = (props: TreeView.NodeProviderProps<Node>) => {
  const { node, indexPath } = props
  return (
    <TreeView.NodeProvider node={node} indexPath={indexPath}>
      <Show
        when={node.children}
        fallback={
          <TreeView.Item>
            <TreeView.ItemIndicator>
              <CheckSquareIcon />
            </TreeView.ItemIndicator>
            <TreeView.ItemText>
              <FileIcon />
              {node.name}
            </TreeView.ItemText>
          </TreeView.Item>
        }
      >
        <TreeView.Branch>
          <TreeView.BranchControl>
            <TreeView.BranchText>
              <FolderIcon /> {node.name}
            </TreeView.BranchText>
            <TreeView.BranchIndicator>
              <ChevronRightIcon />
            </TreeView.BranchIndicator>
          </TreeView.BranchControl>
          <TreeView.BranchContent>
            <TreeView.BranchIndentGuide />
            <For each={node.children}>
              {(child, index) => <TreeNode node={child} indexPath={[...indexPath, index()]} />}
            </For>
          </TreeView.BranchContent>
        </TreeView.Branch>
      </Show>
    </TreeView.NodeProvider>
  )
}

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

API Reference

Root

PropDefaultType
collection
TreeCollection<T>

The collection of tree nodes

asChild
(props: ParentProps<'div'>) => Element

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

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

The initial expanded items of the tree view. Use this when you do not need to control the state of the tree view.

defaultSelectedValue
string[]

The initial selected items of the tree view. Use this when you do not need to control the state of the tree view.

expandedValue
string[]

The id of the expanded nodes

expandOnClicktrue
boolean

Whether clicking on a branch should open it or not

focusedValue
string

The id of the focused node

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

onExpandedChange
(details: ExpandedChangeDetails) => void

Called when the tree is opened or closed

onFocusChange
(details: FocusChangeDetails) => void

Called when the focused node changes

onSelectionChange
(details: SelectionChangeDetails) => void

Called when the selection changes

selectedValue
string[]

The id of the selected nodes

selectionMode'single'
'multiple' | 'single'

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

typeaheadtrue
boolean

Whether the tree supports typeahead search

unmountOnExitfalse
boolean

Whether to unmount on exit.

BranchContent

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]branch-content
[data-state]"open" | "closed"
[data-depth]The depth of the item
[data-path]The path of the item
[data-value]The value of the item

BranchControl

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]branch-control
[data-path]The path of the item
[data-state]"open" | "closed"
[data-disabled]Present when disabled
[data-selected]Present when selected
[data-focus]Present when focused
[data-value]The value of the item
[data-depth]The depth of the item

BranchIndentGuide

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]branch-indent-guide
[data-depth]The depth of the item

BranchIndicator

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]branch-indicator
[data-state]"open" | "closed"
[data-disabled]Present when disabled
[data-selected]Present when selected
[data-focus]Present when focused

Branch

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]branch
[data-depth]The depth of the item
[data-branch]
[data-value]The value of the item
[data-path]The path of the item
[data-selected]Present when selected
[data-state]"open" | "closed"
[data-disabled]Present when disabled

BranchText

PropDefaultType
asChild
(props: ParentProps<'span'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]branch-text
[data-disabled]Present when disabled
[data-state]"open" | "closed"

BranchTrigger

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]branch-trigger
[data-disabled]Present when disabled
[data-state]"open" | "closed"
[data-value]The value of the item

ItemIndicator

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]item-indicator
[data-disabled]Present when disabled
[data-selected]Present when selected
[data-focus]Present when focused

Item

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]item
[data-path]The path of the item
[data-value]The value of the item
[data-focus]Present when focused
[data-selected]Present when selected
[data-disabled]Present when disabled
[data-depth]The depth of the item

ItemText

PropDefaultType
asChild
(props: ParentProps<'span'>) => Element

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

For more details, read our Composition guide.
Data AttributeValue
[data-scope]tree-view
[data-part]item-text
[data-disabled]Present when disabled
[data-selected]Present when selected
[data-focus]Present when focused

Label

PropDefaultType
asChild
(props: ParentProps<'label'>) => Element

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

For more details, read our Composition guide.

NodeProvider

PropDefaultType
indexPath
number[]

The index path of the tree node

node
NonNullable<T>

The tree node

RootProvider

PropDefaultType
value
UseTreeViewReturn<T>

asChild
(props: ParentProps<'div'>) => Element

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.

Tree

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

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

For more details, read our Composition guide.

Accessibility

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.