svelte-virtual-list Svelte Themes

Svelte Virtual List

๐Ÿ“œ A performant virtual list/scrolling component for Svelte applications - efficiently render large scrollable lists with minimal memory usage

@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
  • ๐Ÿ”„ 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

scroll: Programmatic Scrolling

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!

Usage Example

<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() {
        // Scroll to item 5000 with smooth scrolling and auto alignment
        listRef.scroll({ index: 5000, smoothScroll: true, align: 'auto' })
    }
</script>

<button on:click={goToItem5000}> Scroll to item 5000 </button>
<SvelteVirtualList {items} bind:this={listRef}>
    {#snippet renderItem(item)}
        <div>{item.text}</div>
    {/snippet}
</SvelteVirtualList>

API

  • 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

<button on:click={() => listRef.scroll({ index: 5000, align: 'nearest' })}>
    Scroll to item 5000 (nearest)
</button>

Installation

npm install @humanspeak/svelte-virtual-list

Basic 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>

Advanced Features

Chat Application Example

<script lang="ts">
    import SvelteVirtualList from '@humanspeak/svelte-virtual-list'

    type Message = {
        id: number
        text: string
        timestamp: Date
    }

    const messages: Message[] = Array.from({ length: 100 }, (_, i) => ({
        id: i,
        text: `Message ${i}`,
        timestamp: new Date()
    }))
</script>

<div style="height: 500px;">
    <SvelteVirtualList items={messages} mode="bottomToTop" debug>
        {#snippet renderItem(message)}
            <div class="message-container">
                <p>{message.text}</p>
                <span class="timestamp">
                    {message.timestamp.toLocaleString()}
                </span>
            </div>
        {/snippet}
    </SvelteVirtualList>
</div>

Bottom-to-top mode

Use mode="bottomToTop" for chat-like lists anchored to the bottom. Programmatic scrolling uses the same API as top-to-bottom lists:

<script lang="ts">
    import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
    let listRef
    const messages = Array.from({ length: 2000 }, (_, i) => ({ id: i, text: `Msg ${i}` }))
</script>

<SvelteVirtualList items={messages} mode="bottomToTop" bind:this={listRef} />
<button on:click={() => listRef.scroll({ index: messages.length - 1, align: 'bottom' })}>
    Jump to latest
</button>

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)

Testing

  • Unit tests (Vitest): npm test
  • E2E tests (Playwright):
    • One-time: npx playwright install
    • Run: npm run test:e2e

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

License

MIT ยฉ Humanspeak, Inc.

Credits

Made with โ™ฅ by Humanspeak

Top categories

Loading Svelte Themes