VirtualList
Headless virtual scrolling utility. Renders only visible items for lists with thousands of rows.
import { createVirtualList } from 'phoundry-ui'; 10,000 Items
Rendering 0 of 10,000 items
Show code
import { createVirtualList } from 'phoundry-ui';
const vl = createVirtualList({
count: 10000,
itemHeight: 32,
overscan: 5,
});
<div use:vl.action class="h-64 overflow-auto border rounded" onscroll={vl.handleScroll}>
<div style="height: {vl.totalHeight}px; position: relative;">
{#each vl.items as item}
<div
style="position: absolute; top: {item.start}px; height: {item.size}px; width: 100%;"
class="flex items-center px-3 text-sm border-b"
>
Row {item.index}
</div>
{/each}
</div>
</div>Variable row heights
Every 9th row is taller — itemHeight as a function recomputes offsets cumulatively.
Show code
const vl = createVirtualList({
count: 800,
itemHeight: (i) => (i % 9 === 0 ? 52 : 30),
});
<button onclick={() => vl.scrollToIndex(400, 'center')}>Jump</button>Options
| Prop | Type | Default | Description |
|---|---|---|---|
| count required | number | — | Total logical rows. Use an options object with a `get count()` getter if the backing array length changes — reads rerun whenever scroll geometry updates. |
| itemHeight required | number | (index: number) => number | — | Fixed height or per-item height function. |
| overscan | number | 5 | Extra items rendered above and below the viewport. |
Returns
| Prop | Type | Default | Description |
|---|---|---|---|
| items | VirtualItem[] | — | Visible items with index, start position, and size. |
| totalHeight | number | — | Total scrollable height in pixels. |
| scrollOffset | number | — | Current scroll offset. |
| containerHeight | number | — | Measured container height. |
| handleScroll | (e: Event) => void | — | Scroll event handler to attach to the container. |
| scrollToIndex | (index: number, align?: "start" | "center" | "end" | "auto") => void | — | Scroll so the given index is visible; defaults to smart (“auto”) scrolling. |
| action | Action | — | Svelte use:action for the scroll container. |
Usage tips
- This is a headless utility — you provide the container and item markup. Use
use:vl.actionon the scroll container. - For variable-height items, pass a function to
itemHeight— e.g.(i) => i % 5 === 0 ? 48 : 32. - Increase
overscanif you see flickering during fast scrolling. - Use
scrollToIndexfor keyboard navigation or “scroll to top/bottom” buttons.