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
npm install @humanspeak/svelte-virtual-list










A high-performance virtual list component for Svelte 5 applications that efficiently renders large datasets with minimal memory usage.
- π Dynamic item height handling - no fixed height required
- π Bi-directional scrolling support (top-to-bottom and bottom-to-top)
- π 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
You can now programmatically scroll to any item in the list using the scroll method. This is useful for chat apps, jump-to-item navigation, and more. You can check the usage in src/routes/tests/scroll. Thank you for the feature request!
``svelte
{#snippet renderItem(item)}
{item.text}
{/snippet}
`
- scroll(options: { index: number; smoothScroll?: boolean; shouldThrowOnBounds?: boolean; align?: 'auto' | 'top' | 'bottom' | 'nearest' })index
- : The item index to scroll to (0-based)smoothScroll
- : If true, uses smooth scrolling (default: true)shouldThrowOnBounds
- : If true, throws if index is out of bounds (default: true)align
- : Where to align the item in the viewport:'auto'
- (default): Only scroll if not visible, align to top or bottom as appropriate'top'
- : Always align to the top'bottom'
- : Always align to the bottom'nearest'
- : Scroll as little as possible to bring the item into view (like native scrollIntoView({ block: 'nearest' }))
#### Usage Examples
`svelte`
Load more data automatically as users scroll near the end of the list. Perfect for paginated APIs, infinite feeds, and chat applications.
`svelte
{#snippet renderItem(item)}
{item.text}
{/snippet}
`
| Prop | Type | Default | Description |
| ------------------- | ----------------------------- | ------- | ---------------------------------------------------- |
| onLoadMore | () => void \| Promise | - | Callback when more data is needed (supports async) |loadMoreThreshold
| | number | 20 | Number of items from the end to trigger onLoadMore |hasMore
| | boolean | true | Set to false when all data has been loaded |
- Triggers when scrolling near the end of the list
- Automatically triggers on mount if initial items are below threshold
- Prevents concurrent onLoadMore calls while loadingtopToBottom
- Works with both sync and async callbacks
- Supports both and bottomToTop modes
- Infinite Scroll with Convex - Real-time data + pagination with Convex backend
`bashUsing npm
npm install @humanspeak/svelte-virtual-list
Basic Usage
`svelte
{#snippet renderItem(item)}
{item.text}
{/snippet}
`Advanced Features
$3
`svelte
{#snippet renderItem(message)}
{/snippet}
`$3
Use
mode="bottomToTop" for chat-like lists anchored to the bottom. Programmatic scrolling uses the same API as top-to-bottom lists:`svelte
`Props
| Prop | Type | Default | Description |
| ---------------------------- | -------------------------------- | --------------- | ----------------------------------------------------------------------------- |
|
items | T[] | Required | Array of items to render |
| defaultEstimatedItemHeight | number | 40 | Initial height estimate used until items are measured |
| mode | 'topToBottom' \| 'bottomToTop' | 'topToBottom' | Scroll direction and anchoring behavior |
| 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 |Testing
$3
`bash
Run unit tests with coverage
pnpm testRun specific test files
pnpm vitest src/lib/utils/throttle.test.ts
`$3
`bash
Install Playwright browsers (one-time setup)
npx playwright installRun all e2e tests
pnpm run test:e2eRun specific e2e test
npx playwright test tests/docs-visit.spec.ts --project=chromiumDebug mode
npx playwright test --debug
`$3
`bash
Start development server
pnpm devStart both package and docs
pnpm run dev:allCheck TypeScript/Svelte
pnpm run checkBuild package
pnpm run buildFormat and lint code
pnpm run lint:fix
`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 efficiencyProject 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$3
`bash
Install dependencies for both packages
pnpm installRun development servers simultaneously
pnpm run dev:allBuild both packages
pnpm run buildRun tests across the workspace
pnpm test:all
``MIT Β© Humanspeak, Inc.
Made with β€οΈ by Humanspeak