Skip to main content
You are viewing Pre-Alpha documentation.
Vuetify0 Logo
Theme
Mode
Accessibility
Vuetify

createVirtual

Virtual scrolling composable for efficiently rendering large lists by only rendering visible items.


IntermediateJan 30, 2026

Usage

The createVirtual composable efficiently renders large lists by only mounting visible items plus a small overscan buffer. Pass an array of items and configure the item height to get back sliced items, scroll handlers, and positioning values.

0 (rendered) / 10000
<script setup lang="ts">
  import { createVirtual } from '@vuetify/v0'
  import { computed, shallowRef } from 'vue'

  const items = shallowRef(
    Array.from({ length: 10_000 }, (_, i) => ({
      id: i,
      name: `Item ${i + 1}`,
      value: Math.floor(Math.random() * 1000),
    })),
  )

  const virtual = createVirtual(items, { itemHeight: 40 })
  const {
    element,
    items: virtualItems,
    offset,
    size,
    scroll,
    scrollTo,
  } = virtual

  const stats = computed(() => ({
    total: items.value.length,
    rendered: virtualItems.value.length,
  }))

  const jumpTo = shallowRef('')
  function handleJumpTo () {
    const index = Number.parseInt(jumpTo.value) - 1

    if (index < 0 || index > items.value.length) return

    scrollTo(index)
  }

  function addItems () {
    const newItems = Array.from({ length: 100 }, (_, i) => ({
      id: items.value.length + i,
      name: `Item ${items.value.length + i + 1}`,
      value: Math.floor(Math.random() * 1000),
    }))
    items.value = [...items.value, ...newItems]
  }
</script>

<template>
  <div class="flex flex-col gap-3">
    <div class="flex gap-2 items-center text-sm flex-wrap">
      <input
        v-model="jumpTo"
        class="px-2 py-1 border border-divider bg-surface text-on-surface rounded w-24 flex-1 md:flex-none"
        placeholder="Jump to..."
        type="number"
        @keyup.enter="handleJumpTo"
      >

      <button class="px-3 py-1 border border-divider rounded hover:bg-surface-tint" @click="handleJumpTo">
        Jump
      </button>

      <button class="px-3 py-1 border border-divider rounded hover:bg-surface-tint" @click="addItems">
        Add 100
      </button>

      <span class="text-on-surface opacity-60 ml-auto">
        {{ stats.rendered }} (rendered) / {{ stats.total }}
      </span>
    </div>

    <div
      ref="element"
      class="h-[300px] overflow-y-auto border border-divider rounded"
      @scroll="scroll"
    >
      <div :style="{ height: `${offset}px` }" />

      <div
        v-for="item in virtualItems"
        :key="item.index"
        class="h-[40px] px-4 flex items-center justify-between border-b border-divider hover:bg-surface-tint"
      >
        <span class="font-mono text-sm text-on-surface">{{ item.raw.name }}</span>
        <span class="text-on-surface opacity-60">{{ item.raw.value }}</span>
      </div>

      <div :style="{ height: `${size}px` }" />
    </div>
  </div>
</template>

Architecture

The rendering pipeline transforms scroll events into visible item ranges:

Virtual Rendering Pipeline

Use controls to zoom and pan. Click outside or press Escape to close.

Virtual Rendering Pipeline

API Pattern

FunctionPurpose
createVirtual(items, options)Factory - returns a virtual scrolling context
createVirtualContext(items, options)Factory with DI - returns [useVirtual, provideVirtual, virtual] trinity
useVirtual(namespace?)Injection getter - retrieves provided virtual context

Basic Usage

ts
import { ref } from 'vue'
import { createVirtual } from '@vuetify/v0'

const items = ref(Array.from({ length: 10000 }, (_, i) => ({ id: i })))
const virtual = createVirtual(items, { itemHeight: 40 })

With Dependency Injection

ts
// Create context with DI support
const [useVirtual, provideVirtual, virtual] = createVirtualContext(items, {
  namespace: 'app:virtual',
  overscan: 10,
})

// In parent component
provideVirtual()

// In child component
const virtual = useVirtual()

API Reference

The following API details are for the createVirtual composable.

Functions

createVirtual

(items: Ref<readonly T[], readonly T[]>, _options?: VirtualOptions) => VirtualContext<T>

Virtual scrolling composable for efficiently rendering large lists

createVirtualContext

(items: Ref<readonly T[], readonly T[]>, _options?: VirtualContextOptions) => ContextTrinity<VirtualContext<T>>

Creates a virtual scrolling context with dependency injection support.

useVirtual

(namespace?: string) => VirtualContext<T>

Returns the current virtual context from dependency injection.

Options

itemHeight

string | number

The height of the item.

height

string | number

The height of the container.

overscan

number

The number of extra items to render.

direction

VirtualDirection

The direction of the scrolling.

anchor

VirtualAnchor

The anchor of the scrolling.

anchorSmooth

boolean

Whether to smooth the anchor position.

onStartReached

(distance: number) => void | Promise<void>

The callback to call when the start is reached.

onEndReached

(distance: number) => void | Promise<void>

The callback to call when the end is reached.

startThreshold

number

The threshold for the start.

endThreshold

number

The threshold for the end.

momentum

boolean

Whether to enable momentum scrolling.

elastic

boolean

Whether to enable elastic scrolling.

Properties

element

Ref<HTMLElement, HTMLElement>

The element that is being virtualized.

items

ComputedRef<VirtualItem<T>[]>

The items that are being virtualized.

offset

Readonly<ShallowRef<number>>

The offset of the virtualized items.

size

Readonly<ShallowRef<number>>

The size of the virtualized items.

state

ShallowRef<VirtualState>

The state of the virtualized items.

Methods

scrollTo

(index: number, options?: ScrollToOptions) => void

Scroll to an item by index.

scroll

() => void

The scroll event handler.

scrollend

() => void

The scrollend event handler.

resize

(index: number, height: number) => void

Resize an item by index.

reset

() => void

Reset the virtualized items.

Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/