@wentools/virtual-scroll-svelte
v0.1.0
Published
Svelte 5 adapter for @wentools/virtual-scroll: reactive virtualizer, scroll actions, and infinite scroll
Maintainers
Readme
@wentools/virtual-scroll-svelte
Svelte 5 adapter for @wentools/virtual-scroll: reactive virtualizer, scroll actions, and infinite scroll.
Install
npm install @wentools/virtual-scroll-svelte @wentools/virtual-scroll @wentools/simmerVite config: Exclude from optimizeDeps so Svelte runes are compiled by your build pipeline:
// vite.config.ts
optimizeDeps: {
exclude: ['@wentools/virtual-scroll-svelte']
}Usage
Virtual Scrolling
<script lang="ts">
import { createVirtualizer, virtualScroll, virtualItem } from '@wentools/virtual-scroll-svelte'
const items = Array.from({ length: 10000 }, (_, i) => `Item ${i}`)
const virtualizer = createVirtualizer(() => ({
count: items.length,
estimateSize: () => 48,
overscan: 5,
}))
</script>
<div use:virtualScroll={{ virtualizer }} style="height: 400px; overflow-y: auto;">
<div style="height: {virtualizer.totalSize}px; position: relative;">
{#each virtualizer.items as row (row.index)}
<div
use:virtualItem={{ virtualizer, index: row.index }}
style="position: absolute; top: 0; left: 0; width: 100%; transform: translateY({row.start}px);"
>
{items[row.index]}
</div>
{/each}
</div>
</div>Infinite Scrolling
<script lang="ts">
import { infiniteScroll } from '@wentools/virtual-scroll-svelte'
let items = $state([...initialItems])
const loadMore = async () => {
const next = await fetchMoreItems()
items = [...items, ...next]
}
</script>
<div use:infiniteScroll={{ onLoadMore: loadMore, threshold: 200 }} style="overflow-y: auto;">
{#each items as item}
<div>{item.name}</div>
{/each}
</div>API
createVirtualizer(getOptions)
Creates a reactive virtualizer using Svelte 5 runes.
const virtualizer = createVirtualizer(() => ({
count: number,
estimateSize: (index: number) => number,
overscan?: number, // default: 3
}))Returns Virtualizer:
| Property/Method | Description |
|---|---|
| items | Reactive array of visible VirtualItems |
| totalSize | Total scrollable height in px |
| setScrollOffset(px) | Update from scroll events |
| setContainerHeight(px) | Update from resize events |
| measure(index, size) | Record actual item height |
| measureBatch(entries) | Bulk measurement |
| scrollTo(offset) | Programmatic scroll |
| scrollToIndex(index, { align? }) | Scroll to item ('start', 'center', 'end') |
virtualScroll action
Connects a scroll container to the virtualizer (passive scroll + ResizeObserver).
<div use:virtualScroll={{ virtualizer }}>virtualItem action
Measures a rendered item and feeds its height back to the virtualizer.
<div use:virtualItem={{ virtualizer, index: row.index }}>infiniteScroll action
IntersectionObserver-based infinite scroll with debouncing.
<div use:infiniteScroll={{
onLoadMore: () => void | Promise<void>,
threshold?: number, // px before sentinel triggers (default: 200)
disabled?: boolean, // skip setup (default: false)
debounceMs?: number, // debounce interval (default: 300)
}}>License
MIT
