Skip to content

Virtual scrolling and visibility ​

What this page covers ​

Only the rows inside the viewport are rendered to the DOM. Two things decide that set:

  1. Structurally visible — none of the node's ancestors is collapsed. assembly/tree-visibility.ts rebuilds the whole tree's shown flags with a single pass plus a stack that tracks the rightNode of collapsed ancestors, instead of walking upwards per node. Clearing a search uses the same path, so shown pollution from searching does not linger.
  2. Geometrically in view — the container's scrollTop and height slice out the [start, end) range.

MPTT makes both cheap:

OperationComplexity
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 nodeO(subtree + log N)

Parameters ​

propTypeDefaultDescription
heightstring'100%'Container height. The parent must give it a definite height, otherwise there is no window to slice
widthstring'100%'Container width
lineHeightnumber26Row height in pixels; virtual scrolling converts it into the visible range
fontSizestring'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-motion enabled, 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.