# Tree Collection URL: https://ark-ui.com/docs/collections/tree-collection Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/collections/tree-collection.mdx Working with tree collections in Ark UI --- A tree collection is designed to manage hierarchical data structures like file systems, navigation menus, or organization charts. It provides powerful methods for traversing, manipulating, and querying tree structures. ```ts import { createTreeCollection } from '@ark-ui/react/collection' const treeData = { value: 'root', label: 'Root', children: [ { value: 'folder1', label: 'Folder 1', children: [ { value: 'file1', label: 'File 1.txt' }, { value: 'file2', label: 'File 2.txt' }, ], }, { value: 'folder2', label: 'Folder 2', children: [ { value: 'subfolder1', label: 'Subfolder 1', children: [{ value: 'file3', label: 'File 3.txt' }], }, ], }, ], } const tree = createTreeCollection({ rootNode: treeData }) ``` ### Navigation Methods The tree collection provides various methods to navigate through the hierarchical structure. #### Getting First and Last Nodes ```ts const firstNode = tree.getFirstNode() console.log(firstNode?.value) // "folder1" const lastNode = tree.getLastNode() console.log(lastNode?.value) // "folder2" ``` #### Sequential Navigation Navigate to the next or previous node in the tree traversal order: ```ts const nextNode = tree.getNextNode('file1') console.log(nextNode?.value) // "file2" const previousNode = tree.getPreviousNode('file2') console.log(previousNode?.value) // "file1" ``` ### Hierarchical Relationships #### Parent and Children Get parent and descendant nodes: ```ts // Get parent node const parentNode = tree.getParentNode('file1') console.log(parentNode?.value) // "folder1" // Get all ancestor nodes const ancestors = tree.getParentNodes('file3') console.log(ancestors.map((n) => n.value)) // ["folder2", "subfolder1"] // Get all descendant nodes const descendants = tree.getDescendantNodes('folder1') console.log(descendants.map((n) => n.value)) // ["file1", "file2"] // Get descendant values only const descendantValues = tree.getDescendantValues('folder2') console.log(descendantValues) // ["subfolder1", "file3"] ``` #### Sibling Navigation Navigate between sibling nodes: ```ts // Assuming we have the index path of "file1" const indexPath = tree.getIndexPath('file1') // [0, 0] const nextSibling = tree.getNextSibling(indexPath) console.log(nextSibling?.value) // "file2" const previousSibling = tree.getPreviousSibling(indexPath) console.log(previousSibling) // undefined (no previous sibling) // Get all siblings const siblings = tree.getSiblingNodes(indexPath) console.log(siblings.map((n) => n.value)) // ["file1", "file2"] ``` ### Index Path Operations Work with index paths to identify node positions: ```ts // Get index path for a value const indexPath = tree.getIndexPath('file3') console.log(indexPath) // [1, 0, 0] // Get value from index path const value = tree.getValue([1, 0, 0]) console.log(value) // "file3" // Get full value path (all ancestors + node) const valuePath = tree.getValuePath([1, 0, 0]) console.log(valuePath) // ["folder2", "subfolder1", "file3"] // Get node at specific index path const node = tree.at([1, 0]) console.log(node?.value) // "subfolder1" ``` ### Tree Queries #### Branch and Leaf Detection ```ts // Check if a node is a branch (has children) const folder1Node = tree.findNode('folder1') const isBranch = tree.isBranchNode(folder1Node!) console.log(isBranch) // true // Get all branch values const branchValues = tree.getBranchValues() console.log(branchValues) // ["folder1", "folder2", "subfolder1"] ``` #### Tree Traversal Visit all nodes with custom logic: ```ts tree.visit({ onEnter: (node, indexPath) => { console.log(`Visiting: ${node.value} at depth ${indexPath.length}`) // Skip certain branches if (node.value === 'folder2') { return 'skip' // Skip this branch and its children } }, }) ``` #### Filtering Create a new tree with filtered nodes: ```ts // Keep only nodes that match criteria const filteredTree = tree.filter((node, indexPath) => { return node.value.includes('file') // Only keep files }) console.log(filteredTree.getValues()) // ["file1", "file2", "file3"] ``` ### Tree Manipulation #### Adding Nodes ```ts const newFile = { value: 'newfile', label: 'New File.txt' } // Insert after a specific node const indexPath = tree.getIndexPath('file1') const updatedTree = tree.insertAfter(indexPath!, [newFile]) // Insert before a specific node const updatedTree2 = tree.insertBefore(indexPath!, [newFile]) ``` #### Removing Nodes ```ts const indexPath = tree.getIndexPath('file2') const updatedTree = tree.remove([indexPath!]) console.log(updatedTree.getValues()) // file2 is removed ``` #### Moving Nodes ```ts const fromIndexPaths = [tree.getIndexPath('file1')!] const toIndexPath = tree.getIndexPath('folder2')! const updatedTree = tree.move(fromIndexPaths, toIndexPath) // file1 is now moved under folder2 ``` #### Replacing Nodes ```ts const indexPath = tree.getIndexPath('file1')! const newNode = { value: 'replacedfile', label: 'Replaced File.txt' } const updatedTree = tree.replace(indexPath, newNode) ``` ### Utility Methods #### Flattening Convert the tree to a flat structure: ```ts const flatNodes = tree.flatten() console.log(flatNodes.map((n) => ({ value: n.value, depth: n._indexPath.length }))) // [{ value: "folder1", depth: 1 }, { value: "file1", depth: 2 }, ...] ``` #### Getting All Values ```ts const allValues = tree.getValues() console.log(allValues) // ["folder1", "file1", "file2", "folder2", "subfolder1", "file3"] ``` #### Depth Calculation ```ts const depth = tree.getDepth('file3') console.log(depth) // 3 (root -> folder2 -> subfolder1 -> file3) ``` ### Working with Custom Node Types You can customize how the tree collection interprets your data: ```ts interface CustomNode { id: string name: string items?: CustomNode[] isDisabled?: boolean } const customTree = createTreeCollection({ rootNode: { id: 'root', name: 'Root', items: [ { id: '1', name: 'Item 1', isDisabled: false }, { id: '2', name: 'Item 2', isDisabled: true }, ], }, nodeToValue: (node) => node.id, nodeToString: (node) => node.name, nodeToChildren: (node) => node.items, isNodeDisabled: (node) => node.isDisabled ?? false, }) ``` ### Creating Trees from File Paths Create a tree structure from file paths: ```ts import { createFileTreeCollection } from '@ark-ui/react/collection' const paths = ['src/components/Button.tsx', 'src/components/Input.tsx', 'src/utils/helpers.ts', 'docs/README.md'] const fileTree = createFileTreeCollection(paths) console.log(fileTree.getBranchValues()) // ["src", "components", "utils", "docs"] ``` > **Good to know**: Tree collections are immutable - all modification methods return a new tree instance rather than > modifying the original.