virtual_list

Core virtual-list math.

This module is a Gleam port of TanStack Virtual’s @tanstack/virtual-core — the measurements model, the range-extraction algorithm, and the observer architecture are all faithfully translated from the original TypeScript. Many thanks to Tanner Linsley and the TanStack maintainers; the design is theirs, this is just the translation.

The module itself is pure (no FFI, no DOM): it produces a list of VirtualItems to render given a scroll offset, container size, and item size cache. Adapters (e.g. virtual_list/lustre) wire this up to the runtime, observing scroll and resize events and dispatching them back into the consumer’s model.

Types

pub type Options {
  Options(
    count: Int,
    estimate_size: fn(Int) -> Int,
    overscan: Int,
    padding_start: Int,
    padding_end: Int,
    gap: Int,
    lanes: Int,
    get_item_key: fn(Int) -> String,
  )
}

Constructors

  • Options(
      count: Int,
      estimate_size: fn(Int) -> Int,
      overscan: Int,
      padding_start: Int,
      padding_end: Int,
      gap: Int,
      lanes: Int,
      get_item_key: fn(Int) -> String,
    )

    Arguments

    count

    Total number of items in the list.

    estimate_size

    Estimated size in pixels for an item that hasn’t been measured yet.

    overscan

    Extra rows kept mounted above and below the visible window.

    padding_start

    Padding before the first item, in pixels.

    padding_end

    Padding after the last item, in pixels.

    gap

    Gap between items, in pixels.

    lanes

    Number of lanes (columns for a vertical list, rows for a horizontal one). 1 is the standard single-column case.

    get_item_key

    Stable key per item index (used as the DOM diffing key).

pub type Range {
  Range(start_index: Int, end_index: Int)
}

Constructors

  • Range(start_index: Int, end_index: Int)
pub type VirtualItem {
  VirtualItem(
    key: String,
    index: Int,
    start: Int,
    size: Int,
    end: Int,
    lane: Int,
  )
}

Constructors

  • VirtualItem(
      key: String,
      index: Int,
      start: Int,
      size: Int,
      end: Int,
      lane: Int,
    )

Snapshot of the virtualizer at a point in time. Pure; pass it through the model and rebuild on each tick.

pub opaque type Virtualizer

Values

pub fn container_size(v: Virtualizer) -> Int
pub fn default_options(
  count count: Int,
  estimate_size estimate_size: fn(Int) -> Int,
) -> Options

Sensible defaults: single lane, 1-row overscan, no padding/gap, integer-key extractor. The caller must supply count and estimate_size.

pub fn invalidate_measurements(v: Virtualizer) -> Virtualizer

Drop all cached sizes — useful when the item template changes (e.g. font load, density toggle). The next render falls back to estimate_size.

pub fn measure_item(
  v: Virtualizer,
  key: String,
  size: Int,
) -> Virtualizer

Record a measured size for one item. If the size is unchanged, returns the virtualizer untouched (no rebuild). Otherwise rebuilds the measurements list — this is O(count) but happens only when an item actually resizes.

Sizes <= 0 are ignored. ResizeObserver can briefly report 0 while an element is detaching, mid-transition, or in a display: none ancestor; caching a 0 would collapse subsequent items onto the same start offset and stack them visually.

pub fn measure_item_at(
  v: Virtualizer,
  index: Int,
  size: Int,
) -> Virtualizer

Same as measure_item but takes an item index. Resolves the key via options.get_item_key.

pub fn new(options: Options) -> Virtualizer
pub fn options(v: Virtualizer) -> Options
pub fn scroll_offset(v: Virtualizer) -> Int
pub fn set_container_size(
  v: Virtualizer,
  size: Int,
) -> Virtualizer
pub fn set_count(v: Virtualizer, count: Int) -> Virtualizer

Update the total item count. No-op if the count is unchanged (avoids rebuilding measurements). Use this when the data source grows (e.g. after an infinite-scroll page load) without changing any other option.

pub fn set_options(
  v: Virtualizer,
  options: Options,
) -> Virtualizer

Replace the configuration. Recomputes measurements from cached sizes.

pub fn set_scroll_offset(
  v: Virtualizer,
  offset: Int,
) -> Virtualizer
pub fn total_size(v: Virtualizer) -> Int

Total scrollable size in pixels. Use this to size the spacer element.

pub fn virtual_items(v: Virtualizer) -> List(VirtualItem)

The visible items (plus overscan) given the current scroll offset.

Search Document