Data changes and scroll anchoring

Changing data has two independent effects: records may receive new indexes, and the visible pixel anchor may need to stay in place. Stable keys solve the first; the virtual model’s collection methods and scrolling API solve the second.

Stable identity

Pass getItemKey to VirtualList whenever records can prepend, filter, sort, or reorder. Lit accepts the same resolver as the third virtualRange() argument; Svelte uses the record identifier directly in its keyed each block. Return a unique data identifier, not the current index.

Item identity belongs to the renderer rather than the geometry model. Core continues to own sizes, ranges, measurements, and scroll anchoring without depending on application records.

This keeps framework-local item state and DOM identity attached to the record while its index changes. Solid exposes the current index as an accessor so its item measurement binding also follows a moved keyed owner.

The TanStack Table integrations exercise sorting and filtering with stable row IDs:

Append and follow the end

A feed should follow new messages only while the user is already at the latest message. Once the user scrolls away, appending must preserve their position and offer an explicit way back.

Prepend without moving the visible record

For an index-based insertion, call spliceItems() so cached sizes move with the retained indexes, then restore the captured fractional position with scrollToIndex(). The complete ordering is covered by the tested prepend implementations:

Load more near the rendered end

Subscribe to range changes, guard against duplicate requests, append the result to application data, and let the adapter synchronize itemCount. Do not copy a second loading protocol into the page; use the load-on-demand example, which contains the request guard and cleanup together.

Programmatic scrolling

scrollToIndex(index, options) accepts align: "start" | "center" | "end" | "auto" and behavior: "auto" | "smooth". Measurement convergence is an internal core concern rather than a public retry count. See the scroll-to-item implementations for forms, sticky layout elements, and collection-size changes.