Choose an API level

Every level uses the same VirtualScroller sizes, offsets, anchoring, and item measurement. Choose by DOM ownership, not by expected data size.

LevelUse it whenFramework entry point
List bindingOne viewport contains one virtual blockVirtualList in React, Preact, Solid, and Vue; createVirtualList in Svelte; VirtualController in Lit
Layout primitivesThe viewport, size element, and rendered range need custom nestingFramework refs, attachments, composables, or controller refs
Direct coreThe renderer is canvas, a new adapter, or has no framework lifecycleVirtualScroller and optionally VirtualScrollerLayout

Start with the list binding

It owns the three layout bindings and limits framework updates to the rendered range. The canonical implementations are intentionally kept in examples rather than repeated here.

Move down for custom DOM

Use framework layout primitives when content separates the viewport from the virtual size element, or when the page itself scrolls. The required nesting and style ownership do not change; only the framework binding changes.

Read how virtual layout works before changing the tree. Headers and footers may be siblings of the size element, but the rendered-items element remains inside it.

Use a specialized renderer

Semantic tables often need before/after spacer rows instead of an absolutely positioned block. Two-axis grids need independent row and column models. Those renderers still ask core for range and pixel geometry rather than reimplementing virtualization.

Use direct subscriptions only for values the renderer consumes imperatively. The render ownership guide explains which events require framework child reconciliation and which can stay in core-owned DOM updates.