@humanspeak/svelte-virtual-list
v0.5.2
Published
A lightweight, high-performance virtual list component for Svelte 5 that renders large datasets with minimal memory usage. Features include dynamic height support, smooth scrolling, TypeScript support, and efficient DOM recycling. Ideal for infinite scrol
Downloads
18,773
Maintainers
Readme
@humanspeak/svelte-virtual-list
A high-performance virtual list component for Svelte 5 applications that efficiently renders large datasets with minimal memory usage.
Features
- 📏 Dynamic item height handling - no fixed height required
- 🔄 Automatic resize handling for dynamic content
- 📝 TypeScript support with full type safety
- 🚀 SSR compatible with hydration support
- ✨ Svelte 5 runes and snippets support
- 🎨 Customizable styling with class props
- 🐛 Debug mode for development
- 🎯 Smooth scrolling with configurable buffer zones
- 🧠 Memory-optimized for 10k+ items
- 🧪 Comprehensive test coverage (vitest and playwright)
- 🚀 Progressive initialization for large datasets
- 🕹️ Programmatic scrolling with
scroll - ♾️ Infinite scroll support with
onLoadMore
Requirements
- Svelte 5
- Node.js 18+
Installation
# Using pnpm (recommended)
pnpm add @humanspeak/svelte-virtual-list
# Using npm
npm install @humanspeak/svelte-virtual-list
# Using yarn
yarn add @humanspeak/svelte-virtual-listBasic Usage
<script lang="ts">
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
const items = Array.from({ length: 1000 }, (_, i) => ({
id: i,
text: `Item ${i}`
}))
</script>
<SvelteVirtualList {items}>
{#snippet renderItem(item)}
<div>{item.text}</div>
{/snippet}
</SvelteVirtualList>Props
| Prop | Type | Default | Description |
| ---------------------------- | ----------------------------- | -------- | ----------------------------------------------------------------------------- |
| items | T[] | Required | Array of items to render |
| defaultEstimatedItemHeight | number | 40 | Initial height estimate used until items are measured |
| bufferSize | number | 20 | Number of items rendered outside the viewport |
| debug | boolean | false | Enable debug logging and visualizations |
| containerClass | string | '' | Class for outer container |
| viewportClass | string | '' | Class for scrollable viewport |
| contentClass | string | '' | Class for content wrapper |
| itemsClass | string | '' | Class for items container |
| testId | string | '' | Base test id used in internal test hooks (useful for E2E/tests and debugging) |
| onLoadMore | () => void \| Promise<void> | - | Callback when more data is needed for infinite scroll |
| loadMoreThreshold | number | 20 | Items from end to trigger onLoadMore |
| hasMore | boolean | true | Set to false when all data has been loaded |
Programmatic Scrolling
Scroll to any item in the list using the scroll method. Useful for jump-to-item navigation, search results, and more.
<script lang="ts">
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
let listRef
const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, text: `Item ${i}` }))
function goToItem5000() {
listRef.scroll({ index: 5000, smoothScroll: true, align: 'auto' })
}
</script>
<button onclick={goToItem5000}> Scroll to item 5000 </button>
<SvelteVirtualList {items} bind:this={listRef}>
{#snippet renderItem(item)}
<div>{item.text}</div>
{/snippet}
</SvelteVirtualList>scroll() Options
| Option | Type | Default | Description |
| --------------------- | ------------------------------------------ | -------- | --------------------------------------- |
| index | number | Required | The item index to scroll to (0-based) |
| smoothScroll | boolean | true | Use smooth scrolling animation |
| shouldThrowOnBounds | boolean | true | Throw if index is out of bounds |
| align | 'auto' \| 'top' \| 'bottom' \| 'nearest' | 'auto' | Where to align the item in the viewport |
Alignment options:
'auto'- Only scroll if not visible, align to nearest edge'top'- Always align to the top'bottom'- Always align to the bottom'nearest'- Scroll as little as possible to bring the item into view
Infinite Scroll
Load more data automatically as users scroll near the end of the list. Perfect for paginated APIs, infinite feeds, and activity logs.
<script lang="ts">
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
let items = $state([...initialItems])
let hasMore = $state(true)
async function loadMore() {
const newItems = await fetchMoreItems()
items = [...items, ...newItems]
if (newItems.length === 0) {
hasMore = false
}
}
</script>
<SvelteVirtualList {items} onLoadMore={loadMore} loadMoreThreshold={20} {hasMore}>
{#snippet renderItem(item)}
<div>{item.text}</div>
{/snippet}
</SvelteVirtualList>Infinite Scroll Behavior
- Triggers when scrolling near the end of the list
- Automatically triggers on mount if initial items are below threshold
- Prevents concurrent
onLoadMorecalls while loading - Works with both sync and async callbacks
Integration Guides
- Infinite Scroll with Convex - Real-time data + pagination with Convex backend
Performance Considerations
- The
bufferSizeprop affects memory usage and scroll smoothness - Items are measured and cached for optimal performance
- Dynamic height calculations happen automatically
- Resize observers handle container/content changes
- Virtual DOM updates are batched for efficiency
Testing
Unit Tests (Vitest)
# Run unit tests with coverage
pnpm test
# Run specific test files
pnpm vitest src/lib/utils/throttle.test.tsE2E Tests (Playwright)
# Install Playwright browsers (one-time setup)
npx playwright install
# Run all e2e tests
pnpm run test:e2e
# Run specific e2e test
npx playwright test tests/docs-visit.spec.ts --project=chromium
# Debug mode
npx playwright test --debugProject Structure
This is a PNPM workspace with two packages:
./- Main Svelte Virtual List component package./docs- Documentation site with live demos and examples
Development Commands
# Install dependencies for both packages
pnpm install
# Start development server
pnpm dev
# Start both package and docs
pnpm run dev:all
# Build package
pnpm run build
# Check TypeScript/Svelte
pnpm run check
# Format and lint code (uses Trunk)
trunk fmt
trunk check
# Run all tests
pnpm test:allThis project uses Trunk for formatting and linting. Trunk manages tool versions and runs checks automatically via pre-commit hooks.
License
MIT © Humanspeak, Inc.
Credits
Made with ❤️ by Humanspeak
