Custom Virtualization
useVirtualScroll() — the low-level composable that powers all components. Use it when you need to build a custom virtual container.
type SizeProvider = number | ((index: number) => number)
function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualScrollReturnOptions
itemCount
number | Ref<number>
Total item count.
estimatedItemSize
SizeProvider | Ref<SizeProvider> · default: 50
Estimated item height: number or (index) => number. A Ref triggers a full rebuild when it changes.
overscan
number · default: 3
Extra items rendered outside the viewport.
getScrollElement
() => HTMLElement | null
Returns the scroll container.
pageMode
boolean · default: false
Use window as the scroll container. Read once, not reactive — see note below.
horizontal
boolean · default: false
Virtualize scrollLeft/clientWidth instead of scrollTop/clientHeight, RTL-safe via normalizeScrollLeft. Read once, not reactive — see note below.
motionBlur
boolean · default: false
Track scroll velocity and expose it as blurAmount (px). Off by default — zero cost when disabled.
pageModeandhorizontalare captured fromoptionsonce when the composable is set up — changing them on a live instance has no effect. If you need to switch axes at runtime, remount the component that callsuseVirtualScroll(e.g. via:key).
Return value
visibleRange
Readonly<Ref<VisibleRange>>
{ start, end } — first and last visible item indices.
totalHeight
Readonly<Ref<number>>
Total scrollable size in px along the scroll axis (height, or width when horizontal).
offsetTop
(index: number) => number
Pixel offset of item at index along the scroll axis (top, or left when horizontal).
scrollTo
(index, align?, options?) => void
Scroll to item ('start' | 'center' | 'end' | 'auto'). options.behavior is 'auto' (default, instant) or 'smooth'.
scrollToOffset
(offset: number, options?) => void
Scroll to a raw pixel offset. Same options.behavior.
measureItem
(index, height) => void
Report a measured row height.
handleScroll
() => void
Manually trigger a visible-range recalculation.
blurAmount
Readonly<Ref<number>>
Current motion-blur radius in px. Always 0 unless the motionBlur option is enabled.
Example
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useVirtualScroll } from 'vue-virtual-scroller-kit'
const ITEMS = Array.from({ length: 50_000 }, (_, i) => `Item ${i + 1}`)
const containerRef = ref<HTMLElement | null>(null)
const { visibleRange, totalHeight, offsetTop } = useVirtualScroll({
itemCount: ITEMS.length,
estimatedItemSize: 40,
getScrollElement: () => containerRef.value,
})
</script>
<template>
<div ref="containerRef" style="height: 500px; overflow-y: auto; position: relative">
<div :style="{ height: `${totalHeight}px`, position: 'relative' }">
<div
v-for="i in visibleRange.end - visibleRange.start + 1"
:key="visibleRange.start + i - 1"
:style="{
position: 'absolute',
top: `${offsetTop(visibleRange.start + i - 1)}px`,
width: '100%',
height: '40px',
}"
>
{{ ITEMS[visibleRange.start + i - 1] }}
</div>
</div>
</div>
</template>