---
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>;
```
