docs/research/sources/editor-architecture/tanstack-virtual-and-github-large-surface-virtualization.md
Evidence for the Slate v2 virtualization planning lane.
Sources:
.tmp/slate-v2 source read on 2026-05-03.Latest upstream facts:
@tanstack/[email protected] depends on
@tanstack/[email protected].VirtualItem[] shape but moves the
common single-lane hot path onto flat Float64Array storage with lazy
VirtualItem materialization.resizeItem / dynamic-measurement storms are fixed by internal cache version
tracking instead of cloning the whole size cache.shouldAdjustScrollPositionOnItemSizeChange.takeSnapshot() plus initialMeasurementsCache and initialOffset is the
upstream restoration path for remounting a measured virtual list without
throwing away known item sizes.Current live Slate v2 facts on 2026-05-23:
slate-react depends on @tanstack/react-virtual with range
^3.13.24.@tanstack/[email protected] and
@tanstack/[email protected], so the latest iOS/backward-scroll/core
fast-path release is not actually installed yet.useVirtualizedRootPlan uses the single-lane path, stable runtime-id item
keys, rangeExtractor, measureElement, and Slate-owned missing-range /
DOM coverage policy.useVirtualizedRootPlan.scrollToTopLevelIndex bypasses TanStack for
layout-backed targets by calling rootElement.scrollTo(...) directly. That
loses the new iOS scroll-write deferral path for that branch.Slate decision update:
@tanstack/react-virtual in .tmp/slate-v2 so the lockfile reaches
3.13.25 / [email protected].domStrategy={{ type: 'virtualized', threshold, overscan, estimatedBlockSize }} boundary remains correct.shouldAdjustScrollPositionOnItemSizeChange by default. The
new upstream default is the behavior Slate wants for dynamic-height backward
scroll.lanes unused. Slate's top-level block virtualization wants the
single-lane fast path.virtualizer.scrollToOffset / virtualizer.scrollToIndex where practical,
rather than direct rootElement.scrollTo, so Slate inherits upstream iOS
scroll semantics.takeSnapshot() only as an internal remount/restoration
optimization for large docs. Do not add a public Slate API until a real
remount-jump problem is proven.GitHub did not jump straight to virtualization. The sequence matters:
The reported shape:
Slate implication:
TanStack Virtual provides a headless viewport range engine:
count, getScrollElement, estimateSize;overscan, getItemKey, rangeExtractor, measureElement,
onChange, scrollToIndex;data-index and virtualizer.measureElement;scrollMargin and adjusted transforms.Slate implication:
measureElement for variable block heights;rangeExtractor or a Slate-side corridor rule to retain caret,
composition, selection, and materialization targets;Current live .tmp/slate-v2 source has:
renderingStrategy public prop with full, staged, shell, and
virtualized effective types;@tanstack/react-virtual as a slate-react runtime dependency;useVirtualizedRootPlan using useVirtualizer,
runtime-id item keys, dynamic measurement, retained selected/promoted
indexes, and coalesced missing viewport ranges;type: 'virtualized' option in
packages/slate-react/src/rendering-strategy/create-segment-plan.ts;DOMCoverageReason = 'viewport-virtualization' in
packages/slate-dom/src/plugin/dom-coverage.ts;DOMCoverageBoundary registration in
packages/slate-react/src/rendering-strategy/virtualized-range-boundary.tsx;packages/slate-react/test/rendering-strategy-and-scroll.tsx;site/examples/ts/rendering-strategy-runtime.tsx;Current gap:
previewChars still appears in the virtualized option union even though
viewport virtualization does not render shell previews;RenderingStrategySegmentShell can still register
viewport-virtualization boundaries, which keeps shell and virtualized policy
coupled.Use TanStack Virtual as a viewport range engine for experimental virtualized mode only. Do not let it own Slate's editor semantics, and keep the virtualized adapter visibly decoupled from shell/staged rendering internals.
The Slate-owned layers remain:
DOMCoverageBoundary;The TanStack-owned layer is only: