Overview
Fixed-height windowing primitive for long append-only lists. VirtualList owns a
native vertical scroll container and renders only the visible rows plus overscan;
you own the row markup through the row snippet.
Version 1 requires a fixed itemHeight in pixels. Variable or measured row
heights are intentionally out of scope for this primitive.
Usage
Use stickToBottom for live log tails: appending while the user is already at
the bottom keeps the newest row in view, while appending with the viewport
scrolled up leaves the scroll position unchanged.
When to use
- Rendering thousands of same-height append-only rows such as logs, event streams, or activity feeds.
- You need a reusable primitive that owns native vertical scrolling but leaves row markup to a snippet.
- Rows have substantially variable heights that must be measured dynamically — v1 requires a fixed itemHeight.
- Rendering columns or two-dimensional grids — use data-grid for grid semantics and column virtualization.
Examples
10,000 item virtual list
A native scroll container rendering only the visible slice of a 10,000 item append-only event stream.
Props
| Name | Type | Default | Required | Bindable | Description |
|---|---|---|---|---|---|
items | readonly Item[] | req | Items in full logical order. Only the visible window is mounted. | ||
itemHeight | number | req | Fixed row height in pixels. Variable and measured row heights are out of scope for v1; pass the known or estimated fixed height for every row. | ||
overscan | number | 5 | Extra rows rendered before and after the visible window. Defaults to 5. | ||
height | text | '20rem' | CSS block-size for the native scroll container.
Defaults to "20rem". | ||
stickToBottom | boolean | false | When true, appending items while the viewport is already at the bottom keeps the newest item pinned in view. Appending while scrolled up leaves the scroll position unchanged. | ||
tabindex | number | 0 | Override the default focus behavior. The component sets tabindex="0"
by default so keyboard users can reach the native scroll container for
arrow-key scrolling. Pass tabindex={-1} when the viewport should be
programmatically focusable without entering the tab order. | ||
getKey | (item: Item, index: number) => VirtualListKey | Stable key extractor. Omit only when items are append-only and never reordered; the component will fall back to full-array indexes. | |||
row | snippet | req | Rendered row snippet. Receives the item and its virtual row context. | ||
role | unknown | 'list' | |||
onscroll | unknown | req |