VirtualTreeView
A virtualized tree view component that only renders visible items for efficient rendering of large trees. Use this when you have thousands of items and need smooth scrolling performance.
When to Use
- Large datasets: Trees with 1,000+ items
- Performance critical: When smooth scrolling is essential
- Deep hierarchies: Deeply nested structures with many expanded nodes
For smaller trees (< 500 items), the regular TreeView component works well.
Large Dataset Demo (5,000+ items)
This demo shows a tree with over 5,000 items. Despite the large dataset, scrolling remains smooth because only visible items are rendered.
import { VirtualTreeView, useTreeState } from "@vuer-ai/vuer-uikit";
function LargeTreeDemo() {
const [hoveredId, setHoveredId] = useState(null);
// Large dataset with 5000+ items
const { visibleData, expandedItems, toggleItem, hasDescendants } = useTreeState({
data: largeFileSystemData,
defaultExpanded: true,
});
return (
<VirtualTreeView
data={visibleData}
getIcon={getFileIcon}
height={400}
hoveredId={hoveredId}
onItemHover={setHoveredId}
expandedItems={expandedItems}
onToggleItem={toggleItem}
hasDescendants={hasDescendants}
/>
);
}
Performance Comparison
Compare the VirtualTreeView (left) with the regular TreeView (right). Try scrolling both - the virtual version maintains consistent performance.
// VirtualTreeView - only renders visible items
<VirtualTreeView
data={visibleData}
getIcon={getFileIcon}
height={300}
expandedItems={expandedItems}
onToggleItem={toggleItem}
hasDescendants={hasDescendants}
/>
// Regular TreeView - renders all items
<TreeView
data={visibleData}
getIcon={getFileIcon}
expandedItems={expandedItems}
onToggleItem={toggleItem}
hasDescendants={hasDescendants}
/>
With Selection
VirtualTreeView supports all the selection features of the regular TreeView:
- Single click: Select one item
- Ctrl/Cmd + click: Toggle selection
- Shift + click: Range selection
function SelectableVirtualTree() {
const [selectedIds, setSelectedIds] = useState(new Set());
return (
<VirtualTreeView
data={visibleData}
getIcon={getFileIcon}
height={350}
isSelectable
selectedItemIds={selectedIds}
onSelectionChange={setSelectedIds}
expandedItems={expandedItems}
onToggleItem={toggleItem}
hasDescendants={hasDescendants}
/>
);
}
Deeply Nested Tree
Handles deeply nested hierarchies efficiently. Click "Expand All" to see all 1,300+ nodes rendered smoothly.
function DeepTreeDemo() {
const { visibleData, expandedItems, toggleItem, hasDescendants, expandAll, collapseAll } =
useTreeState({
data: deepTreeData,
defaultExpanded: false,
});
return (
<>
<div className="flex gap-2 mb-2">
<button onClick={expandAll}>Expand All</button>
<button onClick={collapseAll}>Collapse All</button>
</div>
<VirtualTreeView
data={visibleData}
getIcon={getFileIcon}
height={350}
expandedItems={expandedItems}
onToggleItem={toggleItem}
hasDescendants={hasDescendants}
/>
</>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | TreeDataItemWithMeta<T>[] | - | Processed tree data from useTreeState |
getIcon | (item: T, expanded?: boolean) => ReactNode | - | Icon renderer function |
height | number | string | '100%' | Container height (required for virtualization) |
overscan | number | 5 | Extra items to render outside visible area |
expandedItems | Set<string> | - | Set of expanded item IDs |
onToggleItem | (id: string) => void | - | Expand/collapse handler |
hoveredId | string | null | - | Currently hovered item ID |
onItemHover | (id: string | null) => void | - | Hover change handler |
isSelectable | boolean | false | Enable item selection |
selectedItemIds | Set<string> | - | Set of selected item IDs |
onSelectionChange | (ids: Set<string>) => void | - | Selection change handler |
selectionMode | 'single' | 'multi' | 'multi' | Selection mode |
hideExpand | boolean | false | Hide expand buttons |
hasDescendants | (id: string) => boolean | () => false | Check if item has children |
renderLabel | (label: string, id: string) => ReactNode | - | Custom label renderer |
renderContextMenu | (item: T) => ReactNode | - | Context menu renderer |
className | string | - | Additional CSS classes |
Usage
import { VirtualTreeView, useTreeState } from '@vuer-ai/vuer-uikit';
function MyFileTree({ data }) {
const [hoveredId, setHoveredId] = useState(null);
const {
visibleData,
expandedItems,
toggleItem,
hasDescendants,
} = useTreeState({
data,
defaultExpanded: true,
});
const getIcon = (item, expanded) => {
if (item.type === 'folder') {
return expanded ? <FolderOpen /> : <Folder />;
}
return <File />;
};
return (
<VirtualTreeView
data={visibleData}
getIcon={getIcon}
height={500}
overscan={5}
hoveredId={hoveredId}
onItemHover={setHoveredId}
expandedItems={expandedItems}
onToggleItem={toggleItem}
hasDescendants={hasDescendants}
/>
);
}
Key Differences from TreeView
| Feature | VirtualTreeView | TreeView |
|---|---|---|
| Rendering | Only visible items | All items |
| Performance with 10k items | Smooth | Laggy |
| Initial render | Fast | Slow for large data |
| Memory usage | Low | High for large data |
height prop | Required | Optional |
Migration from TreeView
To migrate from TreeView to VirtualTreeView:
- Import
VirtualTreeViewinstead ofTreeView - Add a
heightprop (required for virtualization) - Optionally configure
overscanfor smoother scrolling
- import { TreeView } from '@vuer-ai/vuer-uikit';
+ import { VirtualTreeView } from '@vuer-ai/vuer-uikit';
- <TreeView
+ <VirtualTreeView
data={visibleData}
getIcon={getIcon}
+ height={400}
expandedItems={expandedItems}
onToggleItem={toggleItem}
hasDescendants={hasDescendants}
/>