Skip to main content

Large tree

This controlled tree has 21,110 nodes: 10 roots, each with 10 children, 100 grandchildren and 2,000 leaves. Check Item 1 to select its 2,000 leaves at once.

Selected leaves: 0

Show code
LargeTreeExample.tsx
import { useState } from 'react';
import TreeSelect, { getSelectedIDs } from '@attebyte/react-tree-select';
import { ExampleNode, generateTree } from './data';

// 10 roots, 100 children, 1,000 grandchildren and 20,000 leaves: 21,110 nodes.
// Selecting a node only re-renders the nodes whose state changed.
export default function LargeTreeExample() {
const [data, setData] = useState<ExampleNode[]>(() => generateTree([10, 10, 10, 20]));

const selectedCount = getSelectedIDs(data, {
uniqueIDProperty: 'value',
childrenProperty: 'children',
valueProperty: 'included',
mode: 'leaves'
}).length;

return (
<div>
<p className='mb-2'>Selected leaves: {selectedCount.toLocaleString()}</p>
<div className='max-h-96 overflow-auto'>
<TreeSelect<ExampleNode>
data={data}
onChange={setData}
uniqueIDProperty='value'
labelProperty='label'
childrenProperty='children'
valueProperty='included'
aria-label='Large tree'
/>
</div>
</div>
);
}

Why it stays fast​

  • A selection change copies only the changed nodes and their ancestors. Every other node keeps its identity.
  • Nodes are memoized, so unchanged nodes don't re-render, and collapsed branches aren't rendered at all.
  • Expansion and focus state are tracked per node, so expanding one node doesn't re-render the others.

TreeSelect renders every node in an expanded branch. If you need to show tens of thousands of nodes expanded at the same time, consider virtualizing the list.