Large Trees
A tree with thousands of visible nodes stays smooth without any extra dependency.
2,550 nodes total — only the rows in view are mounted.
Show code
<TreeKit data={data} virtualized height={360} />| Prop | Type | Default | Description |
|---|---|---|---|
| virtualized | boolean | false | Only mount rows currently within the scroll viewport (plus overscan). |
| height | number | — | Required with virtualized — fixed pixel height of the scroll viewport. |
| overscan | number | 6 | Extra rows rendered above/below the viewport, to reduce blank flashes on fast scroll. |
| rowHeight | number | 32 | Fixed row height in pixels — required for virtualization's scroll-position math. |
Why this works without a windowing dependency
TreeKit's internal architecture always computes a flat array of currently-visible rows (respecting expansion and any active search filter) before rendering — getVisibleEntries, run once per render via useMemo. This flat list is exactly the shape a virtualization layer needs: a stable, indexable array where item i is always at a known scroll offset (i × rowHeight). Turning on virtualized slices that array to the range currently in view and absolutely-positions each row — no separate library, no re-architecture.
O(n) selection, not O(n) per click
Indeterminate/checked state for the whole tree is computed in a single linear pass (see Indeterminate State), memoized on (data, checkedIds, selectionPropagation) identity. Checking one node doesn't re-walk the tree once per ancestor — it's one pass regardless of tree depth or checked-set size.
Structural sharing for async loading
When children load lazily (Async Loading), TreeKit merges them into an internal copy of the tree while preserving object identity for every untouched branch — loading one folder's contents doesn't invalidate memoization for sibling folders.
Debounce search on very large trees
searchValue filtering is also O(n) per change. For trees in the tens of thousands of nodes, debounce the value you pass to searchValue (e.g. 150ms) rather than passing raw input state on every keystroke.For most apps — hundreds to low thousands of visible nodes — you likely don't need virtualized at all; TreeKit's default rendering is already efficient enough. Reach for it once you're rendering tens of thousands of rows at once.