# Tree View URL: https://ark-ui.com/docs/components/tree-view Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/tree-view.mdx A component that is used to show a tree hierarchy. --- ## Anatomy ```tsx ``` ## Examples **Example: basic** #### React ```tsx import { TreeView, createTreeCollection } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import styles from 'styles/tree-view.module.css' export const Basic = () => { return ( Tree {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {(nodeState) => node.children ? ( {nodeState.expanded ? : } {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} ) } ) } interface Node { id: string name: string children?: Node[] | undefined } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-solid' import { For } from 'solid-js' import styles from 'styles/tree-view.module.css' export const Basic = () => { return ( Tree {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { return ( {(nodeState) => props.node.children ? ( {nodeState().expanded ? : } {props.node.name} {(child, index) => } ) : ( {props.node.name} ) } ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Tree {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().expanded} {:else} {/if} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Controlled Expanded Pass the `expandedValue` and `onExpandedChange` props to the `TreeView.Root` component to control the expanded state of the tree view. **Example: controlled-expanded** #### React ```tsx import { TreeView, createTreeCollection } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import { useState } from 'react' import styles from 'styles/tree-view.module.css' export const ControlledExpanded = () => { const [expandedValue, setExpandedValue] = useState(['node_modules']) return ( setExpandedValue(expandedValue)} > Tree {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {(nodeState) => node.children ? ( {nodeState.expanded ? : } {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} ) } ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-solid' import { For, createSignal } from 'solid-js' import styles from 'styles/tree-view.module.css' export const ControlledExpanded = () => { const [expandedValue, setExpandedValue] = createSignal(['node_modules']) return ( setExpandedValue(expandedValue)} > Tree {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { return ( {(nodeState) => props.node.children ? ( {nodeState().expanded ? : } {props.node.name} {(child, index) => } ) : ( {props.node.name} ) } ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Tree {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().expanded} {:else} {/if} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Controlled Selection Pass the `selectedValue` and `onSelectionChange` props to the `TreeView.Root` component to control the selected state of the tree view. **Example: controlled-selected** #### React ```tsx import { TreeView, createTreeCollection } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import { useState } from 'react' import styles from 'styles/tree-view.module.css' export const ControlledSelected = () => { const [selectedValue, setSelectedValue] = useState(['package.json']) return ( setSelectedValue(selectedValue)} > Tree {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {(nodeState) => node.children ? ( {nodeState.expanded ? : } {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} ) } ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-solid' import { For, createSignal } from 'solid-js' import styles from 'styles/tree-view.module.css' export const ControlledSelected = () => { const [selectedValue, setSelectedValue] = createSignal(['package.json']) return ( setSelectedValue(selectedValue)} > Tree {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { return ( {(nodeState) => props.node.children ? ( {nodeState().expanded ? : } {props.node.name} {(child, index) => } ) : ( {props.node.name} ) } ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte
Selected: {JSON.stringify(selectedValue)}
Tree {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().expanded} {:else} {/if} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Root Provider An alternative way to control the tree view is to use the `RootProvider` component and the `useTreeView` hook. This way you can access the state and methods from outside the component. **Example: root-provider** #### React ```tsx import { TreeView, createTreeCollection, useTreeView } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import styles from 'styles/tree-view.module.css' export const RootProvider = () => { const treeView = useTreeView({ collection }) return (
selected: {JSON.stringify(treeView.selectedValue)} Tree {collection.rootNode.children?.map((node, index) => ( ))}
) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {(nodeState) => node.children ? ( {nodeState.expanded ? : } {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} ) } ) } interface Node { id: string name: string children?: Node[] | undefined } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection, useTreeView } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-solid' import { For } from 'solid-js' import styles from 'styles/tree-view.module.css' export const RootProvider = () => { const treeView = useTreeView({ collection }) return ( Tree {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { return ( {(nodeState) => props.node.children ? ( {nodeState().expanded ? : } {props.node.name} {(child, index) => } ) : ( {props.node.name} ) } ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Root Provider Tree {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().expanded} {:else} {/if} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Lazy Loading Lazy loading is a feature that allows the tree view to load children of a node on demand (or async). This helps to improve the initial load time and memory usage. To use this, you need to provide the following: - `loadChildren` — A function that is used to load the children of a node. - `onLoadChildrenComplete` — A callback that is called when the children of a node are loaded. Used to update the tree collection. - `childrenCount` — A number that indicates the number of children of a branch node. **Example: async-loading** #### React ```tsx import { TreeView, createTreeCollection, useTreeViewNodeContext } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon, LoaderIcon } from 'lucide-react' import { useState } from 'react' import styles from 'styles/tree-view.module.css' // mock api result const response: Record = { node_modules: [ { id: 'zag-js', name: 'zag-js' }, { id: 'pandacss', name: 'panda' }, { id: '@types', name: '@types', childrenCount: 2 }, ], 'node_modules/@types': [ { id: 'react', name: 'react' }, { id: 'react-dom', name: 'react-dom' }, ], src: [ { id: 'app.tsx', name: 'app.tsx' }, { id: 'index.ts', name: 'index.ts' }, ], } // function to load children of a node function loadChildren(details: TreeView.LoadChildrenDetails): Promise { const value = details.valuePath.join('/') return new Promise((resolve) => { setTimeout(() => { resolve(response[value] ?? []) }, 500) }) } export const AsyncLoading = () => { const [collection, setCollection] = useState(initialCollection) return ( setCollection(e.collection)} > Tree {collection.rootNode.children?.map((node, index) => ( ))} ) } function TreeBranchIcon() { const nodeState = useTreeViewNodeContext() if (nodeState.loading) return return nodeState.expanded ? : } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.children || node.childrenCount ? ( {node.name} {node.children?.map((child, index) => ( ))} ) : ( {node.name} )} ) } interface Node { id: string name: string children?: Node[] childrenCount?: number } const initialCollection = createTreeCollection({ nodeToValue: (node) => node.id, nodeToString: (node) => node.name, rootNode: { id: 'ROOT', name: '', children: [ { id: 'node_modules', name: 'node_modules', childrenCount: 3 }, { id: 'src', name: 'src', childrenCount: 2 }, { 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { SquareCheckBigIcon, ChevronRightIcon, FileIcon, FolderIcon, LoaderCircleIcon } from 'lucide-solid' import { For, createSignal } from 'solid-js' import { useTreeViewNodeContext } from '../use-tree-view-node-context' // mock api result const response: Record = { node_modules: [ { id: 'zag-js', name: 'zag-js' }, { id: 'pandacss', name: 'panda' }, { id: '@types', name: '@types', childrenCount: 2 }, ], 'node_modules/@types': [ { id: 'react', name: 'react' }, { id: 'react-dom', name: 'react-dom' }, ], src: [ { id: 'app.tsx', name: 'app.tsx' }, { id: 'index.ts', name: 'index.ts' }, ], } // function to load children of a node function loadChildren(details: TreeView.LoadChildrenDetails): Promise { const value = details.valuePath.join('/') return new Promise((resolve) => { setTimeout(() => { resolve(response[value] ?? []) }, 1200) }) } export const AsyncLoading = () => { const [collection, setCollection] = createSignal(initialCollection) return ( setCollection(e.collection)} > Tree {(node, index) => } ) } function TreeNodeIndicator() { const nodeState = useTreeViewNodeContext() return nodeState().loading ? : } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.children || node.childrenCount ? ( {node.name} {(child, index) => } ) : ( {node.name} )} ) } interface Node { id: string name: string children?: Node[] childrenCount?: number } const initialCollection = createTreeCollection({ nodeToValue: (node) => node.id, nodeToString: (node) => node.name, rootNode: { id: 'ROOT', name: '', children: [ { id: 'node_modules', name: 'node_modules', childrenCount: 3 }, { id: 'src', name: 'src', childrenCount: 2 }, { 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte (collection = e.collection)} > Tree {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children || node.childrenCount} {#if nodeState().loading} {:else} {/if} {node.name} {#each node.children ?? [] as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Lazy Mount Lazy mounting is a feature that allows the content of a tree view to be rendered only when it is expanded. This is useful for performance optimization, especially when tree content is large or complex. To enable lazy mounting, use the `lazyMount` prop on the `TreeView.Root` component. In addition, the `unmountOnExit` prop can be used in conjunction with `lazyMount` to unmount the tree view content when branches are collapsed, freeing up resources. The next time a branch is expanded, its content will be re-rendered. **Example: lazy-mount** #### React ```tsx import { TreeView, createTreeCollection } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import { useTreeViewNodeContext } from '../use-tree-view-node-context' import styles from 'styles/tree-view.module.css' export const LazyMount = () => { return ( Tree {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeBranchIcon = () => { const { expanded } = useTreeViewNodeContext() return expanded ? : } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.children ? ( {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} )} ) } interface Node { id: string name: string children?: Node[] | undefined } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { SquareCheckBigIcon, ChevronRightIcon, FileIcon, FolderIcon } from 'lucide-solid' import { For, Show } from 'solid-js' interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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 LazyMount = () => { return ( Tree {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.name} } > {node.name} {(child, index) => } ) } ``` #### Vue ```vue ``` #### Svelte ```svelte Tree {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().expanded} {:else} {/if} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Filtering Filtering is useful when you have a large tree and you want to filter the nodes to only show the ones that match the search query. Here's an example that composes the `filter` method from the `TreeCollection` and `useFilter` hook to filter the nodes. **Example: filtering** #### React ```tsx import { useFilter } from '@ark-ui/react/locale' import { TreeView, createTreeCollection, useTreeViewContext } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import { useState } from 'react' import styles from 'styles/tree-view.module.css' import fieldStyles from 'styles/field.module.css' export const Filtering = () => { const { contains } = useFilter({ sensitivity: 'base' }) const [collection, setCollection] = useState(initialCollection) const filter = (value: string) => { const filtered = value.length > 0 ? initialCollection.filter((node) => contains(node.name, value)) : initialCollection setCollection(filtered) } return (
filter(e.target.value)} /> {collection.rootNode.children?.map((node, index) => ( ))}
) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props const tree = useTreeViewContext() const nodeState = tree.getNodeState(props) return ( {nodeState.isBranch ? ( {nodeState.expanded ? : } {node.name} {node.children?.map((child, index) => ( ))} ) : ( {node.name} )} ) } interface Node { id: string name: string children?: Node[] } const initialCollection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { useFilter } from '@ark-ui/solid/locale' import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { SquareCheckBigIcon, ChevronRightIcon, FileIcon, FolderIcon } from 'lucide-solid' import { For, Show, createSignal } from 'solid-js' export const Filtering = () => { const filterFn = useFilter({ sensitivity: 'base' }) const [collection, setCollection] = createSignal(initialCollection) const filter = (value: string) => { const filtered = value.length > 0 ? initialCollection.filter((node) => filterFn().contains(node.name, value)) : initialCollection setCollection(filtered) } return (
filter(e.currentTarget.value)} /> {(node, index) => }
) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.name} } > {node.name} {(child, index) => } ) } interface Node { id: string name: string children?: Node[] } const initialCollection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte
filter(e.currentTarget.value)} /> {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each}
{#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().expanded} {:else} {/if} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Links Tree items can be rendered as links to another page or website. This could be useful for documentation sites. Here's an example that modifies the tree collection to represent an hierarchical link structure. It uses the `asChild` prop to render the tree items as links, passing the `href` prop to a `` element. **Example: links** #### React ```tsx import { TreeView, createTreeCollection } from '@ark-ui/react/tree-view' import { ChevronRightIcon, ExternalLinkIcon, FileIcon } from 'lucide-react' import styles from 'styles/tree-view.module.css' export const Links = () => { return ( Docs {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.children ? ( {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} {node.href?.startsWith('http') && } )} ) } interface Node { id: string name: string href?: string children?: Node[] } const collection = createTreeCollection({ nodeToValue: (node) => node.id, nodeToString: (node) => node.name, rootNode: { id: 'ROOT', name: '', children: [ { id: 'docs', name: 'Documentation', children: [ { id: 'docs/getting-started', name: 'Getting Started', href: '/docs/getting-started' }, { id: 'docs/installation', name: 'Installation', href: '/docs/installation' }, { id: 'docs/components', name: 'Components', children: [ { id: 'docs/components/accordion', name: 'Accordion', href: '/docs/components/accordion' }, { id: 'docs/components/dialog', name: 'Dialog', href: '/docs/components/dialog' }, { id: 'docs/components/menu', name: 'Menu', href: '/docs/components/menu' }, ], }, ], }, { id: 'examples', name: 'Examples', children: [ { id: 'examples/react', name: 'React Examples', href: '/examples/react' }, { id: 'examples/vue', name: 'Vue Examples', href: '/examples/vue' }, { id: 'examples/solid', name: 'Solid Examples', href: '/examples/solid' }, ], }, { id: 'external', name: 'External Links', children: [ { id: 'external/github', name: 'GitHub Repository', href: 'https://github.com/chakra-ui/zag' }, { id: 'external/npm', name: 'NPM Package', href: 'https://www.npmjs.com/package/@zag-js/core' }, { id: 'external/docs', name: 'Official Docs', href: 'https://zagjs.com' }, ], }, { id: 'readme.md', name: 'README.md', href: '/readme' }, { id: 'license', name: 'LICENSE', href: '/license' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, ExternalLinkIcon, FileIcon } from 'lucide-solid' import { For, Show } from 'solid-js' export const Links = () => { return ( Docs {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( }> {node.name} } > {node.name} {(child, index) => } ) } interface Node { id: string name: string href?: string children?: Node[] } const collection = createTreeCollection({ nodeToValue: (node) => node.id, nodeToString: (node) => node.name, rootNode: { id: 'ROOT', name: '', children: [ { id: 'docs', name: 'Documentation', children: [ { id: 'docs/getting-started', name: 'Getting Started', href: '/docs/getting-started' }, { id: 'docs/installation', name: 'Installation', href: '/docs/installation' }, { id: 'docs/components', name: 'Components', children: [ { id: 'docs/components/accordion', name: 'Accordion', href: '/docs/components/accordion' }, { id: 'docs/components/dialog', name: 'Dialog', href: '/docs/components/dialog' }, { id: 'docs/components/menu', name: 'Menu', href: '/docs/components/menu' }, ], }, ], }, { id: 'examples', name: 'Examples', children: [ { id: 'examples/react', name: 'React Examples', href: '/examples/react' }, { id: 'examples/vue', name: 'Vue Examples', href: '/examples/vue' }, { id: 'examples/solid', name: 'Solid Examples', href: '/examples/solid' }, ], }, { id: 'external', name: 'External Links', children: [ { id: 'external/github', name: 'GitHub Repository', href: 'https://github.com/chakra-ui/zag' }, { id: 'external/npm', name: 'NPM Package', href: 'https://www.npmjs.com/package/@zag-js/core' }, { id: 'external/docs', name: 'Official Docs', href: 'https://zagjs.com' }, ], }, { id: 'readme.md', name: 'README.md', href: '/readme' }, { id: 'license', name: 'LICENSE', href: '/license' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Docs {#each collection.rootNode.children ?? [] as node, index (node.id)} {/each} ``` ### Virtualized For large tree views with thousands of nodes, virtualization can significantly improve performance by only rendering visible nodes. Key implementation details: - Use `useTreeView` hook with `TreeView.RootProvider` for programmatic control - Pass `scrollToIndexFn` to enable keyboard navigation within the virtualized list - Use `getVisibleNodes()` to get the flattened list of currently visible nodes **Example: virtualized** #### React ```tsx import { TreeView, createTreeCollection, useTreeView } from '@ark-ui/react/tree-view' import { useVirtualizer, type Virtualizer } from '@tanstack/react-virtual' import { ChevronRightIcon, FileIcon, FolderIcon } from 'lucide-react' import { useRef } from 'react' import { flushSync } from 'react-dom' import button from 'styles/button.module.css' import styles from 'styles/tree-view.module.css' interface Node { id: string name: string children?: Node[] } function generateLargeTree(): Node { const folders: Node[] = [] for (let i = 0; i < 50; i++) { const children: Node[] = [] for (let j = 0; j < 20; j++) { children.push({ id: `folder-${i}/file-${i}-${j}.ts`, name: `file-${i}-${j}.ts` }) } folders.push({ id: `folder-${i}`, name: `folder-${i}`, children }) } return { id: 'ROOT', name: '', children: folders, } } const collection = createTreeCollection({ nodeToValue: (node) => node.id, nodeToString: (node) => node.name, rootNode: generateLargeTree(), }) const ROW_HEIGHT = 32 export const Virtualized = () => { const treeRef = useRef(null) const virtualizerRef = useRef | null>(null) const tree = useTreeView({ collection, scrollToIndexFn(details) { flushSync(() => { virtualizerRef.current?.scrollToIndex(details.index, { align: 'auto' }) }) }, }) const visibleNodes = tree.getVisibleNodes() const virtualizer = useVirtualizer({ count: visibleNodes.length, getScrollElement: () => treeRef.current, estimateSize: () => ROW_HEIGHT, overscan: 10, }) virtualizerRef.current = virtualizer return ( Virtualized Tree ({visibleNodes.length} visible nodes)
{virtualizer.getVirtualItems().map((virtualItem) => { const { node, indexPath } = visibleNodes[virtualItem.index] const nodeState = tree.getNodeState({ node, indexPath }) return (
{ if (e.button !== 0) return tree.focus(node.id) }} style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: `${virtualItem.size}px`, transform: `translateY(${virtualItem.start}px)`, }} > {nodeState.isBranch ? ( {node.name} ) : ( {node.name} )}
) })}
) } ``` #### Solid ```tsx import { TreeView, createTreeCollection, useTreeView } from '@ark-ui/solid/tree-view' import { createVirtualizer, type Virtualizer } from '@tanstack/solid-virtual' import { ChevronRightIcon, FileIcon, FolderIcon } from 'lucide-solid' import { For } from 'solid-js' import button from 'styles/button.module.css' import styles from 'styles/tree-view.module.css' interface Node { id: string name: string children?: Node[] } function generateLargeTree(): Node { const folders: Node[] = [] for (let i = 0; i < 50; i++) { const children: Node[] = [] for (let j = 0; j < 20; j++) { children.push({ id: `folder-${i}/file-${i}-${j}.ts`, name: `file-${i}-${j}.ts` }) } folders.push({ id: `folder-${i}`, name: `folder-${i}`, children }) } return { id: 'ROOT', name: '', children: folders, } } const collection = createTreeCollection({ nodeToValue: (node) => node.id, nodeToString: (node) => node.name, rootNode: generateLargeTree(), }) const ROW_HEIGHT = 32 export const Virtualized = () => { let treeRef: HTMLDivElement | undefined let virtualizerRef: Virtualizer | undefined const tree = useTreeView({ collection, scrollToIndexFn(details) { virtualizerRef?.scrollToIndex(details.index, { align: 'auto' }) }, }) const visibleNodes = () => tree().getVisibleNodes() const virtualizer = createVirtualizer({ get count() { return visibleNodes().length }, getScrollElement: () => treeRef ?? null, estimateSize: () => ROW_HEIGHT, overscan: 10, }) virtualizerRef = virtualizer return ( Virtualized Tree ({visibleNodes().length} visible nodes)
{(virtualItem) => { const visibleNode = () => visibleNodes()[virtualItem.index] const nodeState = () => tree().getNodeState({ node: visibleNode().node, indexPath: visibleNode().indexPath }) return (
{ if (e.button !== 0) return tree().focus(visibleNode().node.id) }} style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: `${virtualItem.size}px`, transform: `translateY(${virtualItem.start}px)`, }} > {nodeState().isBranch ? ( {visibleNode().node.name} ) : ( {visibleNode().node.name} )}
) }}
) } ``` #### Vue ```vue ``` #### Svelte ```svelte Virtualized Tree ({visibleNodes.length} visible nodes)
{#each $virtualizer.getVirtualItems() as virtualItem (visibleNodes[virtualItem.index].node.id)} {@const visibleNode = visibleNodes[virtualItem.index]} {@const nodeState = tree().getNodeState({ node: visibleNode.node, indexPath: visibleNode.indexPath })}
{ if (e.button !== 0) return tree().focus(visibleNode.node.id) }} style="position: absolute; top: 0; left: 0; width: 100%; height: {virtualItem.size}px; transform: translateY({virtualItem.start}px);" > {#if nodeState.isBranch} {visibleNode.node.name} {:else} {visibleNode.node.name} {/if}
{/each}
``` ### Checkbox Tree Use the `defaultCheckedValue` prop to enable checkbox selection mode. This allows users to select multiple nodes with checkboxes, including parent-child selection relationships. **Example: checkbox-tree** #### React ```tsx import { TreeView, createTreeCollection } from '@ark-ui/react/tree-view' import { CheckIcon, ChevronRightIcon, MinusIcon } from 'lucide-react' import styles from 'styles/tree-view.module.css' export const CheckboxTree = () => { return ( Tree {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNodeCheckbox = (props: TreeView.NodeCheckboxProps) => { return ( }> ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.children ? ( {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} )} ) } interface Node { id: string name: string children?: Node[] | undefined } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { SquareCheckBigIcon, ChevronRightIcon, SquareMinusIcon, SquareIcon } from 'lucide-solid' import { For } from 'solid-js' export const CheckboxTree = () => { return ( Tree {(node, index) => } ) } const TreeNodeCheckbox = () => { return ( } fallback={}> ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {node.children ? ( {node.name} {(child, index) => } ) : ( {node.name} )} ) } interface Node { id: string name: string children?: Node[] | undefined } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Tree {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet treeNodeCheckbox()} {#snippet indeterminate()} {/snippet} {#snippet fallback()} {/snippet} {/snippet} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#if node.children} {@render treeNodeCheckbox()} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {@render treeNodeCheckbox()} {node.name} {/if} {/snippet} ``` ### Expand and Collapse All Use the `expand()` and `collapse()` methods from the tree view context to programmatically expand or collapse all branches. **Example: expand-collapse-all** #### React ```tsx import { TreeView, createTreeCollection, useTreeViewContext } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import { useMemo } from 'react' import button from 'styles/button.module.css' import styles from 'styles/tree-view.module.css' const ExpandCollapseButtons = () => { const tree = useTreeViewContext() const branchValues = useMemo(() => tree.collection.getBranchValues(), [tree.collection]) const isAllExpanded = useMemo( () => branchValues.every((value) => tree.expandedValue.includes(value)), [tree.expandedValue, branchValues], ) return (
{isAllExpanded ? ( ) : ( )}
) } export const ExpandCollapseAll = () => { return ( {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {(nodeState) => node.children ? ( {nodeState.expanded ? : } {node.name} {node.children.map((child, index) => ( ))} ) : ( {node.name} ) } ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection, useTreeViewContext } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-solid' import { For, Show, createMemo } from 'solid-js' import button from 'styles/button.module.css' import styles from 'styles/tree-view.module.css' const ExpandCollapseButtons = () => { const tree = useTreeViewContext() const branchValues = createMemo(() => tree().collection.getBranchValues()) const isAllExpanded = createMemo(() => branchValues().every((value) => tree().expandedValue.includes(value))) return (
tree().expand()}> Expand all } >
) } export const ExpandCollapseAll = () => { return ( {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { return ( {(nodeState) => ( {props.node.name} } > }> {props.node.name} {(child, index) => } )} ) } interface Node { id: string name: string children?: Node[] } const collection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte {#snippet render(tree)}
{#if branchValues.every((value) => tree().expandedValue.includes(value))} {:else} {/if}
{/snippet}
{#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each}
{#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().expanded} {:else} {/if} {node.name} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {node.name} {/if} {/snippet} {/snippet} ``` ### Mutation Use the collection's `remove()` and `replace()` methods to dynamically add and remove nodes from the tree. This is useful for building file explorer interfaces where users can create and delete files. **Example: mutation** #### React ```tsx import { TreeView, createTreeCollection, useTreeViewContext } from '@ark-ui/react/tree-view' import { ChevronRightIcon, PlusIcon, TrashIcon } from 'lucide-react' import { useState } from 'react' import styles from 'styles/tree-view.module.css' export const Mutation = () => { const [collection, setCollection] = useState(initialCollection) const removeNode = (props: TreeNodeProps) => { setCollection(collection.remove([props.indexPath])) } const addNode = (props: TreeNodeProps) => { const { node, indexPath } = props if (!collection.isBranchNode(node)) return const children = [{ id: `untitled-${Date.now()}`, name: 'untitled.tsx' }, ...(node.children || [])] setCollection(collection.replace(indexPath, { ...node, children })) } return ( {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNodeActions = (props: TreeNodeProps) => { const { onRemove, onAdd, node } = props const tree = useTreeViewContext() const isBranch = tree.collection.isBranchNode(node) return (
{isBranch && ( )}
) } interface TreeNodeProps extends TreeView.NodeProviderProps { onRemove?: (props: TreeView.NodeProviderProps) => void onAdd?: (props: TreeView.NodeProviderProps) => void } const TreeNode = (props: TreeNodeProps) => { const { node, indexPath } = props const tree = useTreeViewContext() const nodeState = tree.getNodeState(props) return ( {nodeState.isBranch ? ( {node.name} {node.children?.map((child, index) => ( ))} ) : ( {node.name} )} ) } interface Node { id: string name: string children?: Node[] } const initialCollection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection, useTreeViewContext } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, PlusIcon, TrashIcon } from 'lucide-solid' import { For, Show, createSignal } from 'solid-js' import styles from 'styles/tree-view.module.css' export const Mutation = () => { const [collection, setCollection] = createSignal(initialCollection) const removeNode = (props: TreeNodeProps) => { setCollection((prev) => prev.remove([props.indexPath])) } const addNode = (props: TreeNodeProps) => { const { node, indexPath } = props const col = collection() if (!col.isBranchNode(node)) return const children = [{ id: `untitled-${Date.now()}`, name: 'untitled.tsx' }, ...(node.children || [])] setCollection(col.replace(indexPath, { ...node, children })) } return ( {(node, index) => } ) } const TreeNodeActions = (props: TreeNodeProps) => { const tree = useTreeViewContext() const isBranch = () => tree().collection.isBranchNode(props.node) return (
) } interface TreeNodeProps extends TreeView.NodeProviderProps { onRemove?: (props: TreeView.NodeProviderProps) => void onAdd?: (props: TreeView.NodeProviderProps) => void } const TreeNode = (props: TreeNodeProps) => { const tree = useTreeViewContext() const nodeState = () => tree().getNodeState(props) return ( {props.node.name} } > {props.node.name} {(child, index) => ( )} ) } interface Node { id: string name: string children?: Node[] } const initialCollection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte {#snippet render(tree)} {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index], tree)} {/each} {/snippet} {#snippet renderNode(node: TreeNode, indexPath: number[], tree: any)} {#if node.children} {node.name}
{#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index], tree)} {/each}
{:else} {node.name}
{/if}
{/snippet} ``` ### Rename Node Enable inline renaming of nodes using the `canRename` prop and `onRenameComplete` callback. Press F2 to activate rename mode on the focused node. **Example: rename-node** #### React ```tsx import { TreeView, createTreeCollection } from '@ark-ui/react/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react' import { useState } from 'react' import styles from 'styles/tree-view.module.css' export const RenameNode = () => { const [collection, setCollection] = useState(initialCollection) return ( true} onRenameComplete={(details) => { setCollection((prev) => { const node = prev.at(details.indexPath) if (!node) return prev return prev.replace(details.indexPath, { ...node, name: details.label }) }) }} > Tree (Press F2 to rename) {collection.rootNode.children?.map((node, index) => ( ))} ) } const TreeNode = (props: TreeView.NodeProviderProps) => { const { node, indexPath } = props return ( {(nodeState) => node.children ? ( {nodeState.renaming ? ( ) : ( {nodeState.expanded ? : } {node.name} )} {node.children.map((child, index) => ( ))} ) : ( {nodeState.renaming ? ( ) : ( {node.name} )} ) } ) } interface Node { id: string name: string children?: Node[] } const initialCollection = createTreeCollection({ 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' }, ], }, }) ``` #### Solid ```tsx import { TreeView, createTreeCollection } from '@ark-ui/solid/tree-view' import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-solid' import { For, Show, createSignal } from 'solid-js' import styles from 'styles/tree-view.module.css' export const RenameNode = () => { const [collection, setCollection] = createSignal(initialCollection) return ( true} onRenameComplete={(details) => { setCollection((prev) => { const node = prev.at(details.indexPath) if (!node) return prev return prev.replace(details.indexPath, { ...node, name: details.label }) }) }} > Tree (Press F2 to rename) {(node, index) => } ) } const TreeNode = (props: TreeView.NodeProviderProps) => { return ( {(nodeState) => ( {props.node.name}} > } > }> {props.node.name} } > {(child, index) => } )} ) } interface Node { id: string name: string children?: Node[] } const initialCollection = createTreeCollection({ 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' }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte true} onRenameComplete={handleRenameComplete}> Tree (Press F2 to rename) {#each collection.rootNode.children ?? [] as node, index (node.id)} {@render renderNode(node, [index])} {/each} {#snippet renderNode(node: TreeNode, indexPath: number[])} {#snippet render(nodeState)} {#if node.children} {#if nodeState().renaming} {:else} {#if nodeState().expanded} {:else} {/if} {node.name} {/if} {#each node.children as child, index (child.id)} {@render renderNode(child, [...indexPath, index])} {/each} {:else} {#if nodeState().renaming} {:else} {node.name} {/if} {/if} {/snippet} {/snippet} ``` ## Guides ### Type Safety The `TreeView.RootComponent` type enables you to create typed wrapper components that maintain full type safety for tree nodes. ```tsx import { TreeView as ArkTreeView } from '@ark-ui/react/tree-view' const TreeView: ArkTreeView.RootComponent = (props) => { return {/* ... */} } ``` Use the wrapper with full type inference on `onSelectionChange` and other callbacks: ```tsx const App = () => { const collection = createTreeCollection({ initialItems: [ { id: '1', label: 'React', children: [] }, { id: '2', label: 'Vue', children: [] }, ], }) return ( { // e.items is typed as Array<{ id: string, label: string, children: [] }> console.log(e.items) }} > {/* ... */} ) } ``` ## API Reference ### Props **Component API Reference** #### React **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `TreeCollection` | Yes | The collection of tree nodes | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `canRename` | `(node: T, indexPath: IndexPath) => boolean` | No | Function to determine if a node can be renamed | | `checkedValue` | `string[]` | No | The controlled checked node value | | `defaultCheckedValue` | `string[]` | No | The initial checked node value when rendered. Use when you don't need to control the checked node value. | | `defaultExpandedValue` | `string[]` | No | The initial expanded node ids when rendered. Use when you don't need to control the expanded node value. | | `defaultFocusedValue` | `string` | No | The initial focused node value when rendered. Use when you don't need to control the focused node value. | | `defaultSelectedValue` | `string[]` | No | The initial selected node value when rendered. Use when you don't need to control the selected node value. | | `expandedValue` | `string[]` | No | The controlled expanded node ids | | `expandOnClick` | `boolean` | No | Whether clicking on a branch should open it or not | | `focusedValue` | `string` | No | The value of the focused node | | `ids` | `Partial<{ root: string; tree: string; label: string; node: (value: string) => string }>` | No | The ids of the tree elements. Useful for composition. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loadChildren` | `(details: LoadChildrenDetails) => Promise` | No | Function to load children for a node asynchronously. When provided, branches will wait for this promise to resolve before expanding. | | `onBeforeRename` | `(details: RenameCompleteDetails) => boolean` | No | Called before a rename is completed. Return false to prevent the rename. | | `onCheckedChange` | `(details: CheckedChangeDetails) => void` | No | Called when the checked value changes | | `onExpandedChange` | `(details: ExpandedChangeDetails) => void` | No | Called when the tree is opened or closed | | `onFocusChange` | `(details: FocusChangeDetails) => void` | No | Called when the focused node changes | | `onLoadChildrenComplete` | `(details: LoadChildrenCompleteDetails) => void` | No | Called when a node finishes loading children | | `onLoadChildrenError` | `(details: LoadChildrenErrorDetails) => void` | No | Called when loading children fails for one or more nodes | | `onRenameComplete` | `(details: RenameCompleteDetails) => void` | No | Called when a node label rename is completed | | `onRenameStart` | `(details: RenameStartDetails) => void` | No | Called when a node starts being renamed | | `onSelectionChange` | `(details: SelectionChangeDetails) => void` | No | Called when the selection changes | | `selectedValue` | `string[]` | No | The controlled selected node value | | `selectionMode` | `'multiple' | 'single'` | No | Whether the tree supports multiple selection - "single": only one node can be selected - "multiple": multiple nodes can be selected | | `typeahead` | `boolean` | No | Whether the tree supports typeahead search | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **BranchContent Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchContent Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchControl Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-value]` | The value of the item | | `[data-depth]` | The depth of the item | | `[data-loading]` | Present when loading | **BranchIndentGuide Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchIndentGuide Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-indent-guide | | `[data-depth]` | The depth of the item | **BranchIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Branch Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Branch | **BranchText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-text | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-loading]` | Present when loading | **BranchTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-trigger | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-value]` | The value of the item | | `[data-loading]` | Present when loading | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-indicator | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-depth]` | The depth of the item | **Item CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Item | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-text | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **NodeCheckboxIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `fallback` | `string | number | bigint | boolean | ReactElement> | Iterable | ReactPortal | Promise<...>` | No | | | `indeterminate` | `string | number | bigint | boolean | ReactElement> | Iterable | ReactPortal | Promise<...>` | No | | **NodeCheckbox Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **NodeCheckbox Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | node-checkbox | | `[data-state]` | "checked" | "unchecked" | "indeterminate" | | `[data-disabled]` | Present when disabled | **NodeProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `number[]` | Yes | The index path of the tree node | | `node` | `NonNullable` | No | The tree node | **NodeRenameInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `UseTreeViewReturn` | Yes | | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Tree Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | #### Solid **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `TreeCollection` | Yes | The collection of tree nodes | | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `canRename` | `(node: any, indexPath: IndexPath) => boolean` | No | Function to determine if a node can be renamed | | `checkedValue` | `string[]` | No | The controlled checked node value | | `defaultCheckedValue` | `string[]` | No | The initial checked node value when rendered. Use when you don't need to control the checked node value. | | `defaultExpandedValue` | `string[]` | No | The initial expanded node ids when rendered. Use when you don't need to control the expanded node value. | | `defaultFocusedValue` | `string` | No | The initial focused node value when rendered. Use when you don't need to control the focused node value. | | `defaultSelectedValue` | `string[]` | No | The initial selected node value when rendered. Use when you don't need to control the selected node value. | | `expandedValue` | `string[]` | No | The controlled expanded node ids | | `expandOnClick` | `boolean` | No | Whether clicking on a branch should open it or not | | `focusedValue` | `string` | No | The value of the focused node | | `id` | `string` | No | The unique identifier of the machine. | | `ids` | `Partial<{ root: string; tree: string; label: string; node: (value: string) => string }>` | No | The ids of the tree elements. Useful for composition. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loadChildren` | `(details: LoadChildrenDetails) => Promise` | No | Function to load children for a node asynchronously. When provided, branches will wait for this promise to resolve before expanding. | | `onBeforeRename` | `(details: RenameCompleteDetails) => boolean` | No | Called before a rename is completed. Return false to prevent the rename. | | `onCheckedChange` | `(details: CheckedChangeDetails) => void` | No | Called when the checked value changes | | `onExpandedChange` | `(details: ExpandedChangeDetails) => void` | No | Called when the tree is opened or closed | | `onFocusChange` | `(details: FocusChangeDetails) => void` | No | Called when the focused node changes | | `onLoadChildrenComplete` | `(details: LoadChildrenCompleteDetails) => void` | No | Called when a node finishes loading children | | `onLoadChildrenError` | `(details: LoadChildrenErrorDetails) => void` | No | Called when loading children fails for one or more nodes | | `onRenameComplete` | `(details: RenameCompleteDetails) => void` | No | Called when a node label rename is completed | | `onRenameStart` | `(details: RenameStartDetails) => void` | No | Called when a node starts being renamed | | `onSelectionChange` | `(details: SelectionChangeDetails) => void` | No | Called when the selection changes | | `selectedValue` | `string[]` | No | The controlled selected node value | | `selectionMode` | `'multiple' | 'single'` | No | Whether the tree supports multiple selection - "single": only one node can be selected - "multiple": multiple nodes can be selected | | `typeahead` | `boolean` | No | Whether the tree supports typeahead search | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **BranchContent Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchContent Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchControl Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-value]` | The value of the item | | `[data-depth]` | The depth of the item | | `[data-loading]` | Present when loading | **BranchIndentGuide Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchIndentGuide Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-indent-guide | | `[data-depth]` | The depth of the item | **BranchIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Branch Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Branch | **BranchText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-text | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-loading]` | Present when loading | **BranchTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-trigger | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-value]` | The value of the item | | `[data-loading]` | Present when loading | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-indicator | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-depth]` | The depth of the item | **Item CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Item | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-text | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'h3'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **NodeCheckboxIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `fallback` | `number | boolean | Node | (string & {}) | ArrayElement` | No | | | `indeterminate` | `number | boolean | Node | (string & {}) | ArrayElement` | No | | **NodeCheckbox Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **NodeCheckbox Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | node-checkbox | | `[data-state]` | "checked" | "unchecked" | "indeterminate" | | `[data-disabled]` | Present when disabled | **NodeProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `number[]` | Yes | The index path of the tree node | | `node` | `NonNullable` | No | The tree node | **NodeRenameInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'input'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `UseTreeViewReturn` | Yes | | | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Tree Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | #### Vue **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `TreeCollection` | Yes | The collection of tree nodes | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `canRename` | `(node: T, indexPath: number[]) => boolean` | No | Function to determine if a node can be renamed | | `checkedValue` | `string[]` | No | The controlled checked node values | | `defaultCheckedValue` | `string[]` | No | The initial checked node values when rendered. Use when you don't need to control the checked node values. | | `defaultExpandedValue` | `string[]` | No | The initial expanded node values when rendered. Use when you don't need to control the expanded node values. | | `defaultFocusedValue` | `string` | No | The initial focused node value when rendered. Use when you don't need to control the focused node value. | | `defaultSelectedValue` | `string[]` | No | The initial selected node values when rendered. Use when you don't need to control the selected node values. | | `expandedValue` | `string[]` | No | The controlled expanded node values | | `expandOnClick` | `boolean` | No | Whether clicking on a branch should open it or not | | `focusedValue` | `string` | No | The id of the focused node | | `id` | `string` | No | The unique identifier of the machine. | | `ids` | `Partial<{ root: string; tree: string; label: string; node(value: string): string }>` | No | The ids of the tree elements. Useful for composition. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loadChildren` | `(details: LoadChildrenDetails) => Promise` | No | A function that loads the children of a node. | | `selectedValue` | `string[]` | No | The controlled selected node values | | `selectionMode` | `'single' | 'multiple'` | No | Whether the tree supports multiple selection - "single": only one node can be selected - "multiple": multiple nodes can be selected | | `typeahead` | `boolean` | No | Whether the tree supports typeahead search | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **BranchContent Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchContent Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchControl Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-value]` | The value of the item | | `[data-depth]` | The depth of the item | | `[data-loading]` | Present when loading | **BranchIndentGuide Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchIndentGuide Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-indent-guide | | `[data-depth]` | The depth of the item | **BranchIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Branch Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Branch | **BranchText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-text | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-loading]` | Present when loading | **BranchTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **BranchTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-trigger | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-value]` | The value of the item | | `[data-loading]` | Present when loading | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-indicator | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-depth]` | The depth of the item | **Item CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Item | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-text | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **NodeCheckboxIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `fallback` | `{}` | No | | | `indeterminate` | `{}` | No | | **NodeCheckbox Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **NodeCheckbox Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | node-checkbox | | `[data-state]` | "checked" | "unchecked" | "indeterminate" | | `[data-disabled]` | Present when disabled | **NodeProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `number[]` | Yes | The index path of the tree node | | `node` | `NonNullable` | No | The tree node | **NodeRenameInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `TreeViewApi` | Yes | | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Tree Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | #### Svelte **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `canRename` | `(node: T, indexPath: IndexPath) => boolean` | No | Function to determine if a node can be renamed | | `checkedValue` | `string[]` | No | The controlled checked node value | | `collection` | `TreeCollection` | No | The tree collection data | | `defaultCheckedValue` | `string[]` | No | The initial checked node value when rendered. Use when you don't need to control the checked node value. | | `defaultExpandedValue` | `string[]` | No | The initial expanded node ids when rendered. Use when you don't need to control the expanded node value. | | `defaultFocusedValue` | `string` | No | The initial focused node value when rendered. Use when you don't need to control the focused node value. | | `defaultSelectedValue` | `string[]` | No | The initial selected node value when rendered. Use when you don't need to control the selected node value. | | `expandedValue` | `string[]` | No | The controlled expanded node ids | | `expandOnClick` | `boolean` | No | Whether clicking on a branch should open it or not | | `focusedValue` | `string` | No | The value of the focused node | | `id` | `string` | No | The unique identifier of the machine. | | `ids` | `Partial<{ root: string; tree: string; label: string; node: (value: string) => string }>` | No | The ids of the tree elements. Useful for composition. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loadChildren` | `(details: LoadChildrenDetails) => Promise` | No | Function to load children for a node asynchronously. When provided, branches will wait for this promise to resolve before expanding. | | `onBeforeRename` | `(details: RenameCompleteDetails) => boolean` | No | Called before a rename is completed. Return false to prevent the rename. | | `onCheckedChange` | `(details: CheckedChangeDetails) => void` | No | Called when the checked value changes | | `onExpandedChange` | `(details: ExpandedChangeDetails) => void` | No | Called when the tree is opened or closed | | `onFocusChange` | `(details: FocusChangeDetails) => void` | No | Called when the focused node changes | | `onLoadChildrenComplete` | `(details: LoadChildrenCompleteDetails) => void` | No | Called when a node finishes loading children | | `onLoadChildrenError` | `(details: LoadChildrenErrorDetails) => void` | No | Called when loading children fails for one or more nodes | | `onRenameComplete` | `(details: RenameCompleteDetails) => void` | No | Called when a node label rename is completed | | `onRenameStart` | `(details: RenameStartDetails) => void` | No | Called when a node starts being renamed | | `onSelectionChange` | `(details: SelectionChangeDetails) => void` | No | Called when the selection changes | | `ref` | `Element` | No | | | `selectedValue` | `string[]` | No | The controlled selected node value | | `selectionMode` | `'multiple' | 'single'` | No | Whether the tree supports multiple selection - "single": only one node can be selected - "multiple": multiple nodes can be selected | | `typeahead` | `boolean` | No | Whether the tree supports typeahead search | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **BranchContent Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'ul'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **BranchContent Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **BranchControl Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-value]` | The value of the item | | `[data-depth]` | The depth of the item | | `[data-loading]` | Present when loading | **BranchIndentGuide Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **BranchIndentGuide Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-indent-guide | | `[data-depth]` | The depth of the item | **BranchIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **BranchIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'li'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Branch Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | | `[data-loading]` | Present when loading | **Branch CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Branch | **BranchText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **BranchText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-text | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-loading]` | Present when loading | **BranchTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'button'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **BranchTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | branch-trigger | | `[data-disabled]` | Present when disabled | | `[data-state]` | "open" | "closed" | | `[data-value]` | The value of the item | | `[data-loading]` | Present when loading | **Context Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `render` | `Snippet<[UseTreeViewContext]>` | Yes | | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-indicator | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'li'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[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-renaming]` | | | `[data-depth]` | The depth of the item | **Item CSS Variables:** | Variable | Description | |----------|-------------| | `--depth` | The depth value for the Item | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | item-text | | `[data-disabled]` | Present when disabled | | `[data-selected]` | Present when selected | | `[data-focus]` | Present when focused | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'h3'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **NodeCheckboxIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `fallback` | `Snippet<[]>` | No | | | `indeterminate` | `Snippet<[]>` | No | | **NodeCheckbox Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **NodeCheckbox Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | tree-view | | `[data-part]` | node-checkbox | | `[data-state]` | "checked" | "unchecked" | "indeterminate" | | `[data-disabled]` | Present when disabled | **NodeContext Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `render` | `Snippet<[UseTreeViewNodeContext]>` | Yes | | **NodeProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `number[]` | Yes | | | `node` | `NonNullable` | No | | **NodeRenameInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'input'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `UseTreeViewReturn` | Yes | | | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `ref` | `Element` | No | | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Tree Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'ul'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | ### Context **API:** | Property | Type | Description | |----------|------|-------------| | `collection` | `TreeCollection` | The tree collection data | | `expandedValue` | `string[]` | The value of the expanded nodes. | | `setExpandedValue` | `(value: string[]) => void` | Sets the expanded value | | `selectedValue` | `string[]` | The value of the selected nodes. | | `setSelectedValue` | `(value: string[]) => void` | Sets the selected value | | `checkedValue` | `string[]` | The value of the checked nodes | | `toggleChecked` | `(value: string, isBranch: boolean) => void` | Toggles the checked value of a node | | `setChecked` | `(value: string[]) => void` | Sets the checked value of a node | | `clearChecked` | `VoidFunction` | Clears the checked value of a node | | `getCheckedMap` | `() => CheckedValueMap` | Returns the checked details of branch and leaf nodes | | `getVisibleNodes` | `() => V[]` | Returns the visible nodes as a flat array of nodes and their index path | | `expand` | `(value?: string[]) => void` | Function to expand nodes. If no value is provided, all nodes will be expanded | | `collapse` | `(value?: string[]) => void` | Function to collapse nodes If no value is provided, all nodes will be collapsed | | `select` | `(value?: string[]) => void` | Function to select nodes If no value is provided, all nodes will be selected | | `deselect` | `(value?: string[]) => void` | Function to deselect nodes If no value is provided, all nodes will be deselected | | `focus` | `(value: string) => void` | Function to focus a node by value | | `selectParent` | `(value: string) => void` | Function to select the parent node of the focused node | | `expandParent` | `(value: string) => void` | Function to expand the parent node of the focused node | | `startRenaming` | `(value: string) => void` | Function to start renaming a node by value | | `submitRenaming` | `(value: string, label: string) => void` | Function to submit the rename and update the node label | | `cancelRenaming` | `() => void` | Function to cancel renaming without changes | ## Accessibility Complies with the [Tree View WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/). ### Keyboard Support