https://github.com/humanspeak/svelte-virtual-list
π A performant virtual list/scrolling component for Svelte applications - efficiently render large scrollable lists with minimal memory usage
https://github.com/humanspeak/svelte-virtual-list
infinite-scroll javascript performance svelte sveltekit typescript ui-components virtual-list virtual-scroll web-components
Last synced: 17 days ago
JSON representation
π A performant virtual list/scrolling component for Svelte applications - efficiently render large scrollable lists with minimal memory usage
- Host: GitHub
- URL: https://github.com/humanspeak/svelte-virtual-list
- Owner: humanspeak
- License: mit
- Created: 2025-01-03T00:24:46.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-04-14T19:05:59.000Z (about 2 months ago)
- Last Synced: 2026-04-14T20:29:21.604Z (about 2 months ago)
- Topics: infinite-scroll, javascript, performance, svelte, sveltekit, typescript, ui-components, virtual-list, virtual-scroll, web-components
- Language: TypeScript
- Homepage: https://virtuallist.svelte.page
- Size: 5.91 MB
- Stars: 79
- Watchers: 1
- Forks: 9
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# @humanspeak/svelte-virtual-list
[](https://www.npmjs.com/package/@humanspeak/svelte-virtual-list)
[](https://github.com/humanspeak/svelte-virtual-list/actions/workflows/npm-publish.yml)
[](https://coveralls.io/github/humanspeak/svelte-virtual-list?branch=main)
[](https://github.com/humanspeak/svelte-virtual-list/blob/main/LICENSE)
[](https://www.npmjs.com/package/@humanspeak/svelte-virtual-list)
[](https://github.com/humanspeak/svelte-virtual-list/actions/workflows/codeql.yml)
[](https://packagephobia.com/result?p=@humanspeak/svelte-virtual-list)
[](https://trunk.io)
[](http://www.typescriptlang.org/)
[](https://www.npmjs.com/package/@humanspeak/svelte-virtual-list)
[](https://github.com/humanspeak/svelte-virtual-list/graphs/commit-activity)
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
```bash
# Using pnpm (recommended)
pnpm add @humanspeak/svelte-virtual-list
# Using npm
npm install @humanspeak/svelte-virtual-list
# Using yarn
yarn add @humanspeak/svelte-virtual-list
```
## Basic Usage
```svelte
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
const items = Array.from({ length: 1000 }, (_, i) => ({
id: i,
text: `Item ${i}`
}))
{#snippet renderItem(item)}
{item.text}
{/snippet}
```
## 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` | - | 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.
```svelte
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' })
}
Scroll to item 5000
{#snippet renderItem(item)}
{item.text}
{/snippet}
```
### 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.
```svelte
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
}
}
{#snippet renderItem(item)}
{item.text}
{/snippet}
```
### Infinite Scroll Behavior
- Triggers when scrolling near the end of the list
- Automatically triggers on mount if initial items are below threshold
- Prevents concurrent `onLoadMore` calls while loading
- Works with both sync and async callbacks
### Integration Guides
- [Infinite Scroll with Convex](documentation/CONVEX_INFINITE_SCROLL.md) - Real-time data + pagination with Convex backend
## Performance Considerations
- The `bufferSize` prop 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)
```bash
# Run unit tests with coverage
pnpm test
# Run specific test files
pnpm vitest src/lib/utils/throttle.test.ts
```
### E2E Tests (Playwright)
```bash
# 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 --debug
```
## Project Structure
This is a **PNPM workspace** with two packages:
1. **`./`** - Main Svelte Virtual List component package
2. **`./docs`** - Documentation site with live demos and examples
### Development Commands
```bash
# 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:all
```
This project uses [Trunk](https://trunk.io) for formatting and linting. Trunk manages tool versions and runs checks automatically via pre-commit hooks.
## License
MIT Β© [Humanspeak, Inc.](LICENSE)
## Credits
Made with β€οΈ by [Humanspeak](https://humanspeak.com)