Tools
Tools: Building Complex Tree Views with react-complex-tree in React
2026-01-19
0 views
admin
Prerequisites ## Installation ## Project Setup ## First Example / Basic Usage ## Understanding the Basics ## Practical Example / Building Something Real ## Common Issues / Troubleshooting ## Next Steps ## Summary ## SEO Keywords react-complex-tree is an unopinionated, accessible, and feature-rich tree component for React with multi-select and drag-and-drop capabilities. It offers full keyboard controls, zero dependencies, and a flexible API for building complex tree structures like file explorers, directory browsers, and hierarchical data displays. This guide walks through setting up and creating complex tree views using react-complex-tree with React, from installation to a working implementation. Before you begin, make sure you have: Install react-complex-tree using your preferred package manager: After installation, your package.json should include: react-complex-tree requires wrapping your tree in an environment component and providing a data provider. Let's create a simple tree view. Create a new file src/TreeExample.jsx: This creates a basic tree view with expandable nodes and keyboard navigation. react-complex-tree provides tree view components: Here's an example with more features: Let's build a file explorer with selection and actions: This example demonstrates: Tree not rendering: Make sure your data structure is correct. Each item needs index and data properties. Check that rootItem matches an item index in your data. Items not expanding: Verify that items with children have a children array. Check that viewState is being managed correctly. Selection not working: Ensure onSelectItems handler is provided. Check that items have canMove or canRename set to true. Drag and drop not working: Make sure drag and drop is enabled in the environment. Check browser console for errors related to drag events. Performance issues: For large trees, consider using virtual rendering. Ensure you're not rendering too many items at once. Styling issues: react-complex-tree provides default styles. Override with custom CSS or use the className prop. Check that styles aren't being overridden by global CSS. Now that you have an understanding of react-complex-tree: You've successfully set up react-complex-tree in your React application and created complex tree views with multi-select, drag-and-drop, and keyboard navigation. react-complex-tree provides a powerful, accessible solution for building hierarchical data displays in React applications. react-complex-tree
react-complex-tree tree view
React complex tree component
react-complex-tree installation
React tree view library
react-complex-tree tutorial
React hierarchical data
react-complex-tree example
React drag and drop tree
react-complex-tree setup
React multi-select tree
react-complex-tree getting started
React accessible tree
react-complex-tree advanced usage Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
npm install react-complex-tree Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
npm install react-complex-tree COMMAND_BLOCK:
npm install react-complex-tree CODE_BLOCK:
yarn add react-complex-tree Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
yarn add react-complex-tree CODE_BLOCK:
yarn add react-complex-tree CODE_BLOCK:
pnpm add react-complex-tree Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
pnpm add react-complex-tree CODE_BLOCK:
pnpm add react-complex-tree CODE_BLOCK:
{ "dependencies": { "react-complex-tree": "^5.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "dependencies": { "react-complex-tree": "^5.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" }
} CODE_BLOCK:
{ "dependencies": { "react-complex-tree": "^5.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" }
} COMMAND_BLOCK:
// src/TreeExample.jsx
import React from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const treeData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'Root', children: ['child1', 'child2'] }, child1: { index: 'child1', canMove: true, canRename: true, data: 'Child 1', children: ['grandchild1'] }, child2: { index: 'child2', canMove: true, canRename: true, data: 'Child 2' }, grandchild1: { index: 'grandchild1', canMove: true, canRename: true, data: 'Grandchild 1' } }
}; function TreeExample() { return ( <div style={{ padding: '20px', maxWidth: '400px' }}> <h2>Basic Tree Example</h2> <div style={{ border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(treeData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={{}} > <Tree treeId="tree-1" rootItem="root" treeLabel="Tree Example" /> </UncontrolledTreeEnvironment> </div> </div> );
} export default TreeExample; Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// src/TreeExample.jsx
import React from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const treeData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'Root', children: ['child1', 'child2'] }, child1: { index: 'child1', canMove: true, canRename: true, data: 'Child 1', children: ['grandchild1'] }, child2: { index: 'child2', canMove: true, canRename: true, data: 'Child 2' }, grandchild1: { index: 'grandchild1', canMove: true, canRename: true, data: 'Grandchild 1' } }
}; function TreeExample() { return ( <div style={{ padding: '20px', maxWidth: '400px' }}> <h2>Basic Tree Example</h2> <div style={{ border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(treeData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={{}} > <Tree treeId="tree-1" rootItem="root" treeLabel="Tree Example" /> </UncontrolledTreeEnvironment> </div> </div> );
} export default TreeExample; COMMAND_BLOCK:
// src/TreeExample.jsx
import React from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const treeData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'Root', children: ['child1', 'child2'] }, child1: { index: 'child1', canMove: true, canRename: true, data: 'Child 1', children: ['grandchild1'] }, child2: { index: 'child2', canMove: true, canRename: true, data: 'Child 2' }, grandchild1: { index: 'grandchild1', canMove: true, canRename: true, data: 'Grandchild 1' } }
}; function TreeExample() { return ( <div style={{ padding: '20px', maxWidth: '400px' }}> <h2>Basic Tree Example</h2> <div style={{ border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(treeData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={{}} > <Tree treeId="tree-1" rootItem="root" treeLabel="Tree Example" /> </UncontrolledTreeEnvironment> </div> </div> );
} export default TreeExample; CODE_BLOCK:
// src/App.jsx
import React from 'react';
import TreeExample from './TreeExample';
import './App.css'; function App() { return ( <div className="App"> <TreeExample /> </div> );
} export default App; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// src/App.jsx
import React from 'react';
import TreeExample from './TreeExample';
import './App.css'; function App() { return ( <div className="App"> <TreeExample /> </div> );
} export default App; CODE_BLOCK:
// src/App.jsx
import React from 'react';
import TreeExample from './TreeExample';
import './App.css'; function App() { return ( <div className="App"> <TreeExample /> </div> );
} export default App; COMMAND_BLOCK:
// src/AdvancedTreeExample.jsx
import React, { useState } from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const advancedTreeData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'Documents', children: ['folder1', 'folder2', 'file1'] }, folder1: { index: 'folder1', canMove: true, canRename: true, data: 'Projects', children: ['project1', 'project2'] }, folder2: { index: 'folder2', canMove: true, canRename: true, data: 'Images' }, file1: { index: 'file1', canMove: true, canRename: true, data: 'readme.txt' }, project1: { index: 'project1', canMove: true, canRename: true, data: 'Project 1' }, project2: { index: 'project2', canMove: true, canRename: true, data: 'Project 2' } }
}; function AdvancedTreeExample() { const [viewState, setViewState] = useState({}); return ( <div style={{ padding: '20px', maxWidth: '500px' }}> <h2>Advanced Tree Example</h2> <div style={{ border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(advancedTreeData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={viewState} onViewStateChange={setViewState} > <Tree treeId="tree-1" rootItem="root" treeLabel="File Explorer" /> </UncontrolledTreeEnvironment> </div> </div> );
} export default AdvancedTreeExample; Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// src/AdvancedTreeExample.jsx
import React, { useState } from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const advancedTreeData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'Documents', children: ['folder1', 'folder2', 'file1'] }, folder1: { index: 'folder1', canMove: true, canRename: true, data: 'Projects', children: ['project1', 'project2'] }, folder2: { index: 'folder2', canMove: true, canRename: true, data: 'Images' }, file1: { index: 'file1', canMove: true, canRename: true, data: 'readme.txt' }, project1: { index: 'project1', canMove: true, canRename: true, data: 'Project 1' }, project2: { index: 'project2', canMove: true, canRename: true, data: 'Project 2' } }
}; function AdvancedTreeExample() { const [viewState, setViewState] = useState({}); return ( <div style={{ padding: '20px', maxWidth: '500px' }}> <h2>Advanced Tree Example</h2> <div style={{ border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(advancedTreeData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={viewState} onViewStateChange={setViewState} > <Tree treeId="tree-1" rootItem="root" treeLabel="File Explorer" /> </UncontrolledTreeEnvironment> </div> </div> );
} export default AdvancedTreeExample; COMMAND_BLOCK:
// src/AdvancedTreeExample.jsx
import React, { useState } from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const advancedTreeData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'Documents', children: ['folder1', 'folder2', 'file1'] }, folder1: { index: 'folder1', canMove: true, canRename: true, data: 'Projects', children: ['project1', 'project2'] }, folder2: { index: 'folder2', canMove: true, canRename: true, data: 'Images' }, file1: { index: 'file1', canMove: true, canRename: true, data: 'readme.txt' }, project1: { index: 'project1', canMove: true, canRename: true, data: 'Project 1' }, project2: { index: 'project2', canMove: true, canRename: true, data: 'Project 2' } }
}; function AdvancedTreeExample() { const [viewState, setViewState] = useState({}); return ( <div style={{ padding: '20px', maxWidth: '500px' }}> <h2>Advanced Tree Example</h2> <div style={{ border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(advancedTreeData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={viewState} onViewStateChange={setViewState} > <Tree treeId="tree-1" rootItem="root" treeLabel="File Explorer" /> </UncontrolledTreeEnvironment> </div> </div> );
} export default AdvancedTreeExample; COMMAND_BLOCK:
// src/FileExplorer.jsx
import React, { useState } from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const fileExplorerData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'My Files', children: ['docs', 'images', 'downloads'] }, docs: { index: 'docs', canMove: true, canRename: true, data: 'Documents', children: ['doc1', 'doc2'] }, images: { index: 'images', canMove: true, canRename: true, data: 'Images', children: ['img1', 'img2'] }, downloads: { index: 'downloads', canMove: true, canRename: true, data: 'Downloads' }, doc1: { index: 'doc1', canMove: true, canRename: true, data: 'Report.pdf' }, doc2: { index: 'doc2', canMove: true, canRename: true, data: 'Presentation.pptx' }, img1: { index: 'img1', canMove: true, canRename: true, data: 'photo1.jpg' }, img2: { index: 'img2', canMove: true, canRename: true, data: 'photo2.png' } }
}; function FileExplorer() { const [viewState, setViewState] = useState({}); const [selectedItems, setSelectedItems] = useState([]); const handleSelectItems = (items) => { setSelectedItems(items); console.log('Selected items:', items); }; return ( <div style={{ display: 'flex', height: '500px', padding: '20px' }}> <div style={{ width: '300px', border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <h3>File Explorer</h3> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(fileExplorerData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={viewState} onViewStateChange={setViewState} onSelectItems={handleSelectItems} > <Tree treeId="tree-1" rootItem="root" treeLabel="Files" /> </UncontrolledTreeEnvironment> </div> <div style={{ flex: 1, marginLeft: '20px', padding: '20px', border: '1px solid #ddd', borderRadius: '4px' }}> <h3>Selected Items</h3> {selectedItems.length > 0 ? ( <ul> {selectedItems.map(item => ( <li key={item}>{item}</li> ))} </ul> ) : ( <p>No items selected</p> )} </div> </div> );
} export default FileExplorer; Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// src/FileExplorer.jsx
import React, { useState } from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const fileExplorerData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'My Files', children: ['docs', 'images', 'downloads'] }, docs: { index: 'docs', canMove: true, canRename: true, data: 'Documents', children: ['doc1', 'doc2'] }, images: { index: 'images', canMove: true, canRename: true, data: 'Images', children: ['img1', 'img2'] }, downloads: { index: 'downloads', canMove: true, canRename: true, data: 'Downloads' }, doc1: { index: 'doc1', canMove: true, canRename: true, data: 'Report.pdf' }, doc2: { index: 'doc2', canMove: true, canRename: true, data: 'Presentation.pptx' }, img1: { index: 'img1', canMove: true, canRename: true, data: 'photo1.jpg' }, img2: { index: 'img2', canMove: true, canRename: true, data: 'photo2.png' } }
}; function FileExplorer() { const [viewState, setViewState] = useState({}); const [selectedItems, setSelectedItems] = useState([]); const handleSelectItems = (items) => { setSelectedItems(items); console.log('Selected items:', items); }; return ( <div style={{ display: 'flex', height: '500px', padding: '20px' }}> <div style={{ width: '300px', border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <h3>File Explorer</h3> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(fileExplorerData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={viewState} onViewStateChange={setViewState} onSelectItems={handleSelectItems} > <Tree treeId="tree-1" rootItem="root" treeLabel="Files" /> </UncontrolledTreeEnvironment> </div> <div style={{ flex: 1, marginLeft: '20px', padding: '20px', border: '1px solid #ddd', borderRadius: '4px' }}> <h3>Selected Items</h3> {selectedItems.length > 0 ? ( <ul> {selectedItems.map(item => ( <li key={item}>{item}</li> ))} </ul> ) : ( <p>No items selected</p> )} </div> </div> );
} export default FileExplorer; COMMAND_BLOCK:
// src/FileExplorer.jsx
import React, { useState } from 'react';
import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider } from 'react-complex-tree'; const fileExplorerData = { items: { root: { index: 'root', canMove: true, canRename: false, data: 'My Files', children: ['docs', 'images', 'downloads'] }, docs: { index: 'docs', canMove: true, canRename: true, data: 'Documents', children: ['doc1', 'doc2'] }, images: { index: 'images', canMove: true, canRename: true, data: 'Images', children: ['img1', 'img2'] }, downloads: { index: 'downloads', canMove: true, canRename: true, data: 'Downloads' }, doc1: { index: 'doc1', canMove: true, canRename: true, data: 'Report.pdf' }, doc2: { index: 'doc2', canMove: true, canRename: true, data: 'Presentation.pptx' }, img1: { index: 'img1', canMove: true, canRename: true, data: 'photo1.jpg' }, img2: { index: 'img2', canMove: true, canRename: true, data: 'photo2.png' } }
}; function FileExplorer() { const [viewState, setViewState] = useState({}); const [selectedItems, setSelectedItems] = useState([]); const handleSelectItems = (items) => { setSelectedItems(items); console.log('Selected items:', items); }; return ( <div style={{ display: 'flex', height: '500px', padding: '20px' }}> <div style={{ width: '300px', border: '1px solid #ddd', borderRadius: '4px', padding: '10px' }}> <h3>File Explorer</h3> <UncontrolledTreeEnvironment dataProvider={new StaticTreeDataProvider(fileExplorerData.items, (item, data) => ({ ...item, data }))} getItemTitle={item => item.data} viewState={viewState} onViewStateChange={setViewState} onSelectItems={handleSelectItems} > <Tree treeId="tree-1" rootItem="root" treeLabel="Files" /> </UncontrolledTreeEnvironment> </div> <div style={{ flex: 1, marginLeft: '20px', padding: '20px', border: '1px solid #ddd', borderRadius: '4px' }}> <h3>Selected Items</h3> {selectedItems.length > 0 ? ( <ul> {selectedItems.map(item => ( <li key={item}>{item}</li> ))} </ul> ) : ( <p>No items selected</p> )} </div> </div> );
} export default FileExplorer; CODE_BLOCK:
// src/App.jsx
import React from 'react';
import FileExplorer from './FileExplorer';
import './App.css'; function App() { return ( <div className="App"> <FileExplorer /> </div> );
} export default App; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// src/App.jsx
import React from 'react';
import FileExplorer from './FileExplorer';
import './App.css'; function App() { return ( <div className="App"> <FileExplorer /> </div> );
} export default App; CODE_BLOCK:
// src/App.jsx
import React from 'react';
import FileExplorer from './FileExplorer';
import './App.css'; function App() { return ( <div className="App"> <FileExplorer /> </div> );
} export default App; - Node.js version 14.0 or higher installed
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) or create-react-app setup
- Basic knowledge of React hooks (useState, useEffect)
- Familiarity with JavaScript/TypeScript
- Understanding of tree data structures - UncontrolledTreeEnvironment: Environment wrapper for uncontrolled trees
- Tree: Main tree component
- StaticTreeDataProvider: Data provider for static tree data
- ControlledTreeEnvironment: Environment for controlled trees
- TreeItem: Individual tree item component - Data provider: Provides tree data to the environment
- Tree ID: Unique identifier for each tree instance
- Root item: Starting point of the tree
- Item structure: Each item has index, data, and optional children
- View state: Controls expanded/collapsed state - File explorer interface
- Item selection
- View state management
- Keyboard navigation
- Expandable folders
- Custom data provider - Tree not rendering: Make sure your data structure is correct. Each item needs index and data properties. Check that rootItem matches an item index in your data.
- Items not expanding: Verify that items with children have a children array. Check that viewState is being managed correctly.
- Selection not working: Ensure onSelectItems handler is provided. Check that items have canMove or canRename set to true.
- Drag and drop not working: Make sure drag and drop is enabled in the environment. Check browser console for errors related to drag events.
- Performance issues: For large trees, consider using virtual rendering. Ensure you're not rendering too many items at once.
- Styling issues: react-complex-tree provides default styles. Override with custom CSS or use the className prop. Check that styles aren't being overridden by global CSS. - Explore controlled tree environments
- Learn about custom data providers
- Implement drag and drop
- Add search and filtering
- Create custom item renderers
- Integrate with state management
- Check the official repository: https://github.com/lukasbach/react-complex-tree
how-totutorialguidedev.toainodejavascriptgitgithub