Props

All available props for the SvelteVirtualList component.

file · PropsExample.svelte mode · live running source
range · pending measured · 0 ● debug on
Item 0 measured row
Item 1 buffer candidate
Item 2 stable offset
Item 3 stable offset
Item 4 measured row
Item 5 buffer candidate
Item 6 stable offset
Item 7 stable offset
Item 8 measured row
Item 9 buffer candidate
Item 10 stable offset
Item 11 stable offset
Item 12 measured row
Item 13 buffer candidate
Item 14 stable offset
Item 15 stable offset
Item 16 measured row
Item 17 buffer candidate
Item 18 stable offset
Item 19 stable offset
Item 20 measured row
items · 200
visible · pending
avg height · 40px
total height · pending

Required Props

items

The array of items to render.

items: TItem[]
items: TItem[]

renderItem

A Svelte snippet that defines how each item is rendered.

{#snippet renderItem(item, index)}
    <div>{item.text}</div>
{/snippet}
{#snippet renderItem(item, index)}
    <div>{item.text}</div>
{/snippet}

Optional Props

header and footer

Try the interactive header and footer example to resize snippets, preserve your reading position, and explore an empty list.

Type: Snippet | undefined (no arguments)

Always-mounted content before and after the virtualized rows. Both snippets scroll with the list and are not sticky; horizontal mode treats them as leading/trailing content. Border-box measurements include their active-axis sizes in content extent, scroll targets and the physical end. Wrappers isolate child margins without adding spacing. Snippets own their dimensions, including zero-size content.

<SvelteVirtualList {items}>
    {#snippet header()}<h2>Results</h2>{/snippet}
    {#snippet renderItem(item)}<article>{item.title}</article>{/snippet}
    {#snippet footer()}<p>End of results</p>{/snippet}
</SvelteVirtualList>
<SvelteVirtualList {items}>
    {#snippet header()}<h2>Results</h2>{/snippet}
    {#snippet renderItem(item)}<article>{item.title}</article>{/snippet}
    {#snippet footer()}<p>End of results</p>{/snippet}
</SvelteVirtualList>

Short lists place spare space after the footer. Resizing or replacing snippets preserves the visible reading row, keeps physical start at zero and preserves a pinned physical end. Removal and orientation changes refresh measurements. Snippets never consume row indices, alter row averages or count as new data for loading.

itemKey

Returns a stable identity for each item. The key allows cached measurements, rendered DOM, and viewport anchors to follow the same logical item when the array is reordered or changed.

itemKey?: (item: TItem, index: number) => string | number
itemKey?: (item: TItem, index: number) => string | number

Use a unique, stable value from the item rather than its array index:

<SvelteVirtualList {items} itemKey={(item) => item.id}>
    {#snippet renderItem(item)}
        <article>{item.title}</article>
    {/snippet}
</SvelteVirtualList>
<SvelteVirtualList {items} itemKey={(item) => item.id}>
    {#snippet renderItem(item)}
        <article>{item.title}</article>
    {/snippet}
</SvelteVirtualList>

itemKey works with both vertical and horizontal lists. It is strongly recommended when items can be prepended, inserted, removed, reordered, replaced immutably, or retained while orientation changes. Duplicate keys are invalid. A database ID or another persistent domain identifier is normally the right key; an array index is not stable when the collection changes.

With itemKey, the scroll position follows the content through those changes. When items are added or removed above the viewport, the item at the top of the viewport stays where it is; if that item is itself removed, the next remaining item takes its place. The two ends of the list behave differently:

  • At the start, items added before the first item are shown rather than scrolled out of view.
  • At the end, the view stays at the end when an update removes or moves items — for example a log that adds new rows and trims old ones in one update. A plain append does not move the view. Lists that use onLoadMore hold the reading position instead, so a newly loaded page is not skipped.

The prop is optional. Without it, append-only and positionally stable collections work normally. If an unkeyed update makes item identity ambiguous, the component discards affected measurements rather than attaching stale geometry to different items.

bufferSize

Number of items to render outside the visible viewport for smooth scrolling.

bufferSize?: number
// Default: 20
bufferSize?: number
// Default: 20

orientation

Controls the physical layout and scroll axis. It can change reactively at runtime.

orientation?: 'vertical' | 'horizontal'
// Default: 'vertical'
orientation?: 'vertical' | 'horizontal'
// Default: 'vertical'

Horizontal mode uses LTR scrollLeft behavior. RTL horizontal normalization is not currently supported. When switching axes, provide itemKey so the list can preserve the same logical visible item while rebuilding axis-specific measurements.

defaultEstimatedItemSize

Initial estimated size in pixels along the active axis before an item is measured. This means height in vertical mode and width in horizontal mode.

defaultEstimatedItemSize?: number
// Default: 40
defaultEstimatedItemSize?: number
// Default: 40

Use this axis-neutral prop for new code, especially when orientation can change. If both size props are provided, defaultEstimatedItemSize takes precedence.

defaultEstimatedItemHeight

Compatibility alias for the initial item estimate. It remains supported for existing vertical lists; prefer defaultEstimatedItemSize for new or axis-switching lists.

defaultEstimatedItemHeight?: number
// Default: 40
defaultEstimatedItemHeight?: number
// Default: 40

Infinite Scroll Props

onLoadMore

Callback triggered when scrolling near the end of the list.

onLoadMore?: () => void | Promise<void>
onLoadMore?: () => void | Promise<void>

loadMoreThreshold

Number of items from the end to trigger onLoadMore.

loadMoreThreshold?: number
// Default: 20
loadMoreThreshold?: number
// Default: 20

hasMore

Set to false when all data has been loaded.

hasMore?: boolean
// Default: true
hasMore?: boolean
// Default: true

Styling Props

containerClass

CSS class for the outer container element.

containerClass?: string
containerClass?: string

viewportClass

CSS class for the scrollable viewport element.

viewportClass?: string
viewportClass?: string

viewportLabel

Accessible label announced for the scrollable viewport. The viewport renders as a focusable role="region", so keyboard users can Tab to it and operate it with the standard scroll keys (arrows, PageUp/PageDown, Space, Shift+Space, Home, End).

viewportLabel?: string // default: 'Scrollable list'
viewportLabel?: string // default: 'Scrollable list'

contentClass

CSS class for the content wrapper element.

contentClass?: string
contentClass?: string

itemsClass

CSS class for the items wrapper element.

itemsClass?: string
itemsClass?: string

Debug Props

debug

Enable debug mode with visual overlay.

debug?: boolean
// Default: false
debug?: boolean
// Default: false

debugFunction

Custom callback to receive debug information.

debugFunction?: (info: SvelteVirtualListDebugInfo) => void
debugFunction?: (info: SvelteVirtualListDebugInfo) => void

Testing Props

testId

Base test ID for component elements.

testId?: string
testId?: string

When set, adds data-testid attributes:

  • {testId}-container
  • {testId}-viewport
  • {testId}-content
  • {testId}-items