A Morden React tree component library with virtualization, search, and Tailwind CSS support. Demo
Another choice for React tree components.

- Virtual scrolling for large datasets (1000+ nodes)
- Fuzzy search with highlighting and auto-expansion
- Full customization of icons and nodes
- Responsive design for all screen sizes
- TypeScript support with complete type definitions
- Multiple selection modes - single/multi-select, checkboxes, disabled states
- Tailwind CSS integration - works with or without Tailwind
- Tree utilities - connecting lines, click-to-toggle, auto-expand
npm install rstree-uinpm install react react-domWorks with Tailwind CSS v3+ and v4+, or as a standalone component.
Add to your CSS file:
@import "tailwindcss";
@source "../node_modules/rstree-ui";Add the library path to your tailwind.config.js:
module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    "./node_modules/rstree-ui/**/*.{js,ts,jsx,tsx}",
  ],
  // ... other config
}Import the pre-compiled styles:
import 'rstree-ui/style.css'import { RsTree } from 'rstree-ui'
const data = [
  {
    id: '1',
    label: 'Documents',
    children: [
      { id: '1-1', label: 'Resume.pdf' },
      { id: '1-2', label: 'Cover Letter.docx' }
    ]
  },
  { id: '2', label: 'Pictures' }
]
function App() {
  const [selectedIds, setSelectedIds] = useState([])
  
  return (
    <RsTree 
      data={data}
      selectedIds={selectedIds}
      onSelect={setSelectedIds}
      showIcons={true}
    />
  )
}| Prop | Type | Default | Description | 
|---|---|---|---|
| data | TreeNode[] | required | Tree data structure | 
| selectedIds | string[] | [] | Array of selected node IDs | 
| onSelect | (ids: string[]) => void | - | Selection change callback | 
| multiSelect | boolean | false | Enable multi-selection | 
| Prop | Type | Default | Description | 
|---|---|---|---|
| expandedIds | string[] | [] | Array of expanded node IDs | 
| onExpand | (ids: string[]) => void | - | Expansion change callback | 
| clickToToggle | boolean | false | Click anywhere on node to toggle | 
| Prop | Type | Default | Description | 
|---|---|---|---|
| checkable | boolean | false | Enable checkboxes | 
| checkedIds | string[] | [] | Array of checked node IDs | 
| onCheck | (ids: string[]) => void | - | Check state change callback | 
| Prop | Type | Default | Description | 
|---|---|---|---|
| showIcons | boolean | true | Show folder/file icons | 
| showTreeLines | boolean | false | Show connecting lines | 
| disabled | boolean | false | Disable all interactions | 
| className | string | '' | Additional CSS classes for container | 
| treeLineClassName | string | '' | Custom CSS classes for tree lines | 
| treeNodeClassName | string | '' | Custom CSS classes for tree nodes | 
| Prop | Type | Default | Description | 
|---|---|---|---|
| expandIcon | React.ReactNode | <ChevronRight /> | Custom expand icon | 
| collapseIcon | React.ReactNode | <ChevronDown /> | Custom collapse icon | 
| folderIcon | React.ReactNode | <Folder /> | Custom folder icon | 
| fileIcon | React.ReactNode | <File /> | Custom file icon | 
| Prop | Type | Default | Description | 
|---|---|---|---|
| searchTerm | string | '' | Search query string | 
| autoExpandSearch | boolean | true | Auto-expand search results | 
| onSearchMatch | (id: string | null) => void | - | Best match callback | 
| Prop | Type | Default | Description | 
|---|---|---|---|
| virtualizeEnabled | boolean | true | Enable virtual scrolling | 
| height | number | 400 | Fixed height in pixels | 
| itemHeight | number | 32 | Height per item | 
| autoHeight | boolean | false | Auto-adjust height | 
| maxHeight | number | 400 | Maximum height | 
| minHeight | number | 100 | Minimum height | 
| Prop | Type | Description | 
|---|---|---|
| renderNode | (node: TreeNode, props: TreeNodeRenderProps) => React.ReactNode | Custom node renderer | 
| onNodeClick | (node: TreeNode, event: React.MouseEvent) => void | Node click handler | 
interface TreeNode {
  id: string              // Unique identifier
  label: string           // Display text
  children?: TreeNode[]   // Child nodes
  disabled?: boolean      // Disable this node
  icon?: React.ComponentType<{ className?: string }> | ReactNode  // Custom icon for this node
  metadata?: Record<string, unknown>  // Additional metadata
  data?: any             // Additional custom data
}<RsTree
  data={data}
  multiSelect={true}
  selectedIds={selectedIds}
  onSelect={setSelectedIds}
/><RsTree
  data={data}
  checkable={true}
  checkedIds={checkedIds}
  onCheck={setCheckedIds}
/><RsTree
  data={data}
  searchTerm={searchTerm}
  autoExpandSearch={true}
  virtualizeEnabled={true}
/>const MyExpandIcon = <span>βΆ</span>
const MyCollapseIcon = <span>βΌ</span>
<RsTree
  data={data}
  expandIcon={MyExpandIcon}
  collapseIcon={MyCollapseIcon}
  showIcons={true}
/><RsTree
  data={largeDataset}
  height={500}
  virtualizeEnabled={true}
  itemHeight={36}
/>// Custom tree lines and node styling
<RsTree
  data={data}
  showTreeLines={true}
  treeLineClassName="border-blue-300 border-dashed"
  treeNodeClassName="rounded-lg shadow-sm hover:shadow-md"
  className="border border-gray-200 rounded-md"
/>
// Dark theme styling example
<RsTree
  data={data}
  showTreeLines={true}
  treeLineClassName="border-gray-600"
  treeNodeClassName="text-gray-100 hover:bg-gray-800 bg-gray-900"
  className="bg-gray-900 border border-gray-700"
/>The library automatically handles layout structure (indentation, tree lines, expand icons, checkboxes) while allowing you to customize the content area:
// Rich project management tree with custom metadata
const projectData = [
  {
    id: "project-1",
    label: "React Dashboard",
    data: { 
      type: "project", 
      status: "active", 
      priority: "high", 
      lastModified: "2 hours ago" 
    },
    children: [
      { 
        id: "src", 
        label: "src", 
        data: { type: "folder", fileCount: 12, size: "298 KB" }
      },
      { 
        id: "app.tsx", 
        label: "App.tsx", 
        data: { type: "file", language: "typescript", size: "12.5 KB", lines: 340 }
      },
    ]
  }
];
const customRenderer = (node, props) => {
  const { data } = node;
  
  if (data?.type === "project") {
    return (
      <div className="flex items-center gap-3 py-1 w-full min-w-0">
        <div className="flex items-center gap-2 flex-1 min-w-0">
          <span className="font-semibold text-gray-100">{node.label}</span>
          <span className={`px-2 py-0.5 text-xs rounded-full ${
            data.status === 'active' ? 'bg-green-500/20 text-green-400' : 'bg-blue-500/20 text-blue-400'
          }`}>
            {data.status}
          </span>
          <div className="w-2 h-2 rounded-full bg-red-500"></div>
          <span className="text-xs text-gray-400">{data.priority}</span>
        </div>
        <span className="text-xs text-gray-400">π
 {data.lastModified}</span>
      </div>
    );
  }
  
  if (data?.type === "file") {
    return (
      <div className="flex items-center gap-3 py-1 w-full min-w-0">
        <div className="flex items-center gap-2 flex-1 min-w-0">
          <span className="w-6 h-6 bg-gray-700 text-gray-300 rounded text-xs flex items-center justify-center font-mono">
            {data.language === 'typescript' ? 'TS' : 'JS'}
          </span>
          <span className="text-gray-200">{node.label}</span>
        </div>
        <div className="flex items-center gap-3 text-xs text-gray-500">
          <span>{data.lines} lines</span>
          <span>{data.size}</span>
        </div>
      </div>
    );
  }
  
  return <span>{node.label}</span>;
};
<RsTree
  data={projectData}
  renderNode={customRenderer}
  showTreeLines={true}
  multiSelect={true}
/>Key Features:
- β Automatic Layout: Indentation, tree lines, and controls are handled automatically
- β Rich Content: Display badges, icons, metadata, and custom styling
- β Responsive Design: Content adapts to available space with proper text truncation
- β Interaction Support: Maintain full tree functionality (select, expand, check)
Note: Your custom content is automatically wrapped in the standard tree layout structure, so you don't need to handle indentation, tree lines, or control elements yourself. Just focus on the node content.
npm installnpm run dev    # Watch mode
npm run build  # Build library
npm run test   # Run tests
npm run lint   # Lint codenpm run buildnpm run testContributions are welcome!
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- β Star this repository if you find it useful
- π Report bugs
- π‘ Request features