Virtual scrolling and visibility
What this page covers
Only the rows inside the viewport are rendered to the DOM. Two things decide that set:
- Structurally visible — none of the node's ancestors is collapsed.
assembly/tree-visibility.tsrebuilds the whole tree'sshownflags with a single pass plus a stack that tracks therightNodeof collapsed ancestors, instead of walking upwards per node. Clearing a search uses the same path, soshownpollution from searching does not linger. - Geometrically in view — the container's
scrollTopand height slice out the[start, end)range.
MPTT makes both cheap:
| Operation | Complexity |
|---|---|
| Subtree check (is a node inside a subtree) | O(1) — compare the leftNode / rightNode range |
| Viewport slice (rows to render) | O(k), k = rows in viewport |
| Expanding / collapsing one node | O(subtree + log N) |
Parameters
| prop | Type | Default | Description |
|---|---|---|---|
height | string | '100%' | Container height. The parent must give it a definite height, otherwise there is no window to slice |
width | string | '100%' | Container width |
lineHeight | number | 26 | Row height in pixels; virtual scrolling converts it into the visible range |
fontSize | string | '14px' | Font size inside rows |
Expand / collapse and animation
expandAll()/collapseAll()apply to the current view: normally the full tree, and while searching only the current results — never changing the main tree's expansion state.- Expanding or collapsing creates a short-lived transition (about 220ms) only for branch rows already in the viewport; the whole subtree is never added to the DOM for the animation, and unchanged rows are not remounted.
- Scrolling is briefly frozen during the transition so the animation cannot be cut in half.
- With
prefers-reduced-motionenabled, the animation degrades to instantaneous.
Usage
vue
<script setup lang="ts">
import { ref } from 'vue'
import { VueGiantTree } from 'vue3-giant-tree-wasm'
const treeRef = ref<InstanceType<typeof VueGiantTree>>()
const selected = ref([])
</script>
<template>
<div style="height: 600px">
<button @click="treeRef?.expandAll()">Expand all</button>
<button @click="treeRef?.collapseAll()">Collapse all</button>
<VueGiantTree ref="treeRef" :tree="rows" root="root" v-model="selected" />
</div>
</template>Try it
Try it: switch "Data size" to 10k, press "Expand all", then scroll. The tree holds thousands of rows, but the number of DOM rows always depends only on the viewport height.