DEV Community

Justin Clark
Justin Clark

Posted on

Building Complex Tree Views with react-complex-tree in React

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.

Demo animation

Prerequisites

Before you begin, make sure you have:

  • 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

Installation

Install react-complex-tree using your preferred package manager:

npm install react-complex-tree
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add react-complex-tree
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add react-complex-tree
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "react-complex-tree": "^5.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

react-complex-tree requires wrapping your tree in an environment component and providing a data provider.

First Example / Basic Usage

Let's create a simple tree view. Create a new file src/TreeExample.jsx:

// 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

Update your App.jsx:

// 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

This creates a basic tree view with expandable nodes and keyboard navigation.

Understanding the Basics

react-complex-tree provides tree view components:

  • 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

Key concepts:

  • 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

Here's an example with more features:

// 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

Practical Example / Building Something Real

Let's build a file explorer with selection and actions:

// 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

Update your App.jsx:

// 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

This example demonstrates:

  • File explorer interface
  • Item selection
  • View state management
  • Keyboard navigation
  • Expandable folders
  • Custom data provider

Common Issues / Troubleshooting

  1. 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.

  2. Items not expanding: Verify that items with children have a children array. Check that viewState is being managed correctly.

  3. Selection not working: Ensure onSelectItems handler is provided. Check that items have canMove or canRename set to true.

  4. Drag and drop not working: Make sure drag and drop is enabled in the environment. Check browser console for errors related to drag events.

  5. Performance issues: For large trees, consider using virtual rendering. Ensure you're not rendering too many items at once.

  6. 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.

Next Steps

Now that you have an understanding of react-complex-tree:

  • 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

Summary

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.

SEO Keywords

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

Top comments (0)