Virtual

@domphy/virtual renders only the rows/columns currently in view — essential for long lists, grids, and tables — with dynamic measurement, overscan, sticky ranges, and smooth scroll-to.

It is a 1-1 port of @tanstack/virtual-core v3.17.0 (MIT, © Tanner Linsley and the TanStack team). The src/ is byte-identical to upstream, so the entire TanStack Virtual reference applies as-is and future versions can be diffed and merged directly. The only addition is the Domphy adapter in src/domphy/.

The core is framework-agnostic with zero dependencies.

Install

<div class="blocks">
<div class="block active" data-tab="0">
npm install @domphy/virtual @domphy/core
</div>
<div class="block" data-tab="1">

</div>
</div>

@domphy/core is a peer dependency of the adapter only.

Live Example

10,000 rows; only the visible ones are mounted.

Adapter

createVirtualizer(options) (from @domphy/virtual/domphy) owns the scroll element and binds the virtualizer to Domphy reactivity.

import { createVirtualizer } from "@domphy/virtual/domphy"

const list = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  count: rows.length,
  estimateSize: () => 32,
  overscan: 10,
})
MemberDescription
getVirtualItems(l)Reactive list of visible VirtualItems — read with the listener inside the items function.
getTotalSize(l)Reactive total scroll size, for the spacer height/width.
setScrollElement(el)Wire the scroll container DOM node; call from its _onMount.
measureElement(el)Dynamic measurement ref; call from each item's _onMount for variable sizes.
scrollToIndex(i, opts?) / scrollToOffset(px, opts?)Imperative scrolling.
setOptions(opts)Update count/options, then re-measure.
virtualizerThe underlying Virtualizer — the full virtual-core API.
version(l)Raw reactive change counter.
destroy()Detach observers; call from _onRemove.

Wiring

  1. Make the outer element a fixed-height scroll container and wire it: _onMount: (node) => list.setScrollElement(node.domElement).
  2. Inside, render a relative spacer whose height is list.getTotalSize(l).
  3. Map list.getVirtualItems(l) into absolutely-positioned children using each item's start/size, keyed by item.key.
  4. For variable-height rows, call list.measureElement(node.domElement) from each row's _onMount and drop the fixed height.

Pass your own observeElementRect / observeElementOffset / scrollToFn to virtualize against the window instead of an element.