Files
agent-skills/skills/vueuse-functions/references/useVirtualList.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

185 lines
5.0 KiB
Markdown

---
category: Component
---
# useVirtualList
::: warning
Consider using [`vue-virtual-scroller`](https://github.com/Akryum/vue-virtual-scroller) instead, if you are looking for more features.
:::
Create virtual lists with ease. Virtual lists (sometimes called [_virtual scrollers_](https://vue-virtual-scroller-demo.netlify.app/)) allow you to render a large number of items performantly. They only render the minimum number of DOM nodes necessary to show the items within the `container` element by using the `wrapper` element to emulate the container element's full height.
## Usage
### Simple list
```ts
import { useVirtualList } from '@vueuse/core'
const { list, containerProps, wrapperProps } = useVirtualList(
Array.from(Array.from({ length: 99999 }).keys()),
{
// Keep `itemHeight` in sync with the item's row.
itemHeight: 22,
},
)
```
### Config
| State | Type | Description |
| ---------- | -------- | ----------------------------------------------------------------------------------------------- |
| itemHeight | `number` | ensure that the total height of the `wrapper` element is calculated correctly.\* |
| itemWidth | `number` | ensure that the total width of the `wrapper` element is calculated correctly.\* |
| overscan | `number` | number of pre-rendered DOM nodes. Prevents whitespace between items if you scroll very quickly. |
\* The `itemHeight` or `itemWidth` must be kept in sync with the height of each row rendered. If you are seeing extra whitespace or jitter when scrolling to the bottom of the list, ensure the `itemHeight` or `itemWidth` is the same height as the row.
### Reactive list
```ts
import { useToggle, useVirtualList } from '@vueuse/core'
import { computed } from 'vue'
const [isEven, toggle] = useToggle()
const allItems = Array.from(Array.from({ length: 99999 }).keys())
const filteredList = computed(() => allItems.filter(i => isEven.value ? i % 2 === 0 : i % 2 === 1))
const { list, containerProps, wrapperProps } = useVirtualList(
filteredList,
{
itemHeight: 22,
},
)
```
```vue
<template>
<p>Showing {{ isEven ? 'even' : 'odd' }} items</p>
<button @click="toggle">
Toggle Even/Odd
</button>
<div v-bind="containerProps" style="height: 300px">
<div v-bind="wrapperProps">
<div v-for="item in list" :key="item.index" style="height: 22px">
Row: {{ item.data }}
</div>
</div>
</div>
</template>
```
### Horizontal list
```ts
import { useVirtualList } from '@vueuse/core'
const allItems = Array.from(Array.from({ length: 99999 }).keys())
const { list, containerProps, wrapperProps } = useVirtualList(
allItems,
{
itemWidth: 200,
},
)
```
```vue
<template>
<div v-bind="containerProps" style="height: 300px">
<div v-bind="wrapperProps">
<div v-for="item in list" :key="item.index" style="width: 200px">
Row: {{ item.data }}
</div>
</div>
</div>
</template>
```
## Component Usage
```vue
<template>
<UseVirtualList :list="list" :options="options" height="300px">
<template #default="props">
<!-- you can get current item of list here -->
<div style="height: 22px">
Row {{ props.index }} {{ props.data }}
</div>
</template>
</UseVirtualList>
</template>
```
To scroll to a specific element, the component exposes `scrollTo(index: number) => void`.
## Type Declarations
```ts
type UseVirtualListItemSize = number | ((index: number) => number)
export interface UseHorizontalVirtualListOptions
extends UseVirtualListOptionsBase {
/**
* item width, accept a pixel value or a function that returns the width
*
* @default 0
*/
itemWidth: UseVirtualListItemSize
}
export interface UseVerticalVirtualListOptions
extends UseVirtualListOptionsBase {
/**
* item height, accept a pixel value or a function that returns the height
*
* @default 0
*/
itemHeight: UseVirtualListItemSize
}
export interface UseVirtualListOptionsBase {
/**
* the extra buffer items outside of the view area
*
* @default 5
*/
overscan?: number
}
export type UseVirtualListOptions =
| UseHorizontalVirtualListOptions
| UseVerticalVirtualListOptions
export interface UseVirtualListItem<T> {
data: T
index: number
}
export interface UseVirtualListReturn<T> {
list: Ref<UseVirtualListItem<T>[]>
scrollTo: (index: number) => void
containerProps: {
ref: Ref<HTMLElement | null>
onScroll: () => void
style: StyleValue
}
wrapperProps: ComputedRef<{
style:
| {
width: string
height: string
marginTop: string
}
| {
width: string
height: string
marginLeft: string
display: string
}
}>
}
/**
* Please consider using [`vue-virtual-scroller`](https://github.com/Akryum/vue-virtual-scroller) if you are looking for more features.
*/
export declare function useVirtualList<T = any>(
list: MaybeRef<readonly T[]>,
options: UseVirtualListOptions,
): UseVirtualListReturn<T>
```