Vue Virtual Scroller
Use this skill when a task involves large Vue lists, DOM reuse, windowed rendering, or choosing between RecycleScroller, DynamicScroller, WindowScroller, and the headless helpers.
Quick choice
| Surface |
Use it when |
Avoid it when |
RecycleScroller |
Item size is fixed, precomputed, or available from a numeric field or resolver. |
The DOM must measure unknown item size after render. |
DynamicScroller |
Item size is unknown before render and should be measured automatically. |
A fixed-size or pre-sized path already works. |
DynamicScrollerItem |
You are rendering children inside DynamicScroller and the wrapper fits the markup. |
You need wrapper-free semantics such as table rows. |
WindowScroller |
The browser window should drive scrolling for the component path. |
The list should own its own scroll container. |
useRecycleScroller |
You need the virtualization engine with custom markup for known-size or pre-sized items. |
The slot-based components already fit the UI. |
useDynamicScroller |
You need wrapper-free unknown-size measurement with custom markup or semantic table rows. |
DynamicScroller plus DynamicScrollerItem already fits the UI. |
useWindowScroller |
The page should keep scrolling, but you still need headless control over markup and wrappers. |
An inner scroll container is acceptable. |
Setup
vue-virtual-scroller targets Vue 3, ships ESM only, and requires Vue 3.3+ for the generic component typing surface. Use it with an ESM-aware toolchain such as Vite, Nuxt, Rollup, or webpack 5.
pnpm add vue-virtual-scroller
Always import the package CSS:
import 'vue-virtual-scroller/index.css'
Install all bundled components:
import { createApp } from 'vue'
import VueVirtualScroller from 'vue-virtual-scroller'
const app = createApp(App)
app.use(VueVirtualScroller)
Or register/import only what you need:
import { RecycleScroller, WindowScroller } from 'vue-virtual-scroller'
app.component('RecycleScroller', RecycleScroller)
app.component('WindowScroller', WindowScroller)
Workflow
- Decide whether sizes are known before render.
- If sizes are fixed or already stored in data, start with
RecycleScroller or useRecycleScroller.
- If sizes are unknown until the DOM renders, use
DynamicScroller or useDynamicScroller.
- If the page owns scrolling, prefer
WindowScroller or useWindowScroller.
- Set explicit scroll sizing, item sizing, and keying before debugging performance.
Sizing rules
- The scrolling surface must have real dimensions. Inner-scroll paths need a sized container plus overflow.
RecycleScroller supports fixed numeric itemSize, itemSize: null with sizeField, or an itemSize(item, index) resolver.
DynamicScroller and useDynamicScroller require minItemSize for initial layout.
gridItems only works with fixed numeric itemSize.
- Horizontal lists follow the same rules, but sizing applies on width instead of height.
flowMode is a vertical single-axis native-flow path. Use spacer elements from startSpacerSize and endSpacerSize instead of an absolutely positioned inner wrapper.
Practical guidance
Fixed-size vs unknown-size
- Prefer
RecycleScroller for tables, simple rows, grids, and card lists where size is stable or already known in memory.
- Use
DynamicScroller for message feeds, cards, or rows whose rendered content changes height after filtering, editing, or streaming.
- Use headless helpers when the bundled wrapper markup gets in the way of semantics or design-system constraints.
Component vs headless
- Stay on component APIs when the default slot structure already fits the UI.
- Move to
useRecycleScroller for custom markup with known sizes.
- Move to
useDynamicScroller for wrapper-free measurement, especially semantic tables and custom row shells.
- Move to
useWindowScroller when page scrolling is intentional and wrapper control still matters.
Rendering pitfalls
- Reused views mean child components must react when
item changes; do not assume a fresh instance per row.
- Render from
pool, not visiblePool, on headless paths when you want normal recycling behavior.
- Only reach for
watchData when a legacy no-ResizeObserver fallback matters.
- On headless dynamic paths, render from
view.item. Reach for view.itemWithSize only when you need measured metadata.
- Key nested images, but do not add unnecessary keys to the immediate recycled content.
Performance guardrails
emitUpdate, emitResize, and watchData add work; keep them off unless the UI needs them.
- Variable-size mode in
RecycleScroller is heavier than fixed-size mode.
DynamicScroller is heavier than fixed-size virtualization, so use it only when measurement is necessary.
- Browsers still impose large-element limits, so extremely large lists can hit practical ceilings.
Common layouts
- Chat feeds and append-heavy timelines map well to
DynamicScroller or useDynamicScroller.
- Multi-column card galleries map to
RecycleScroller grid mode.
- Page-level search results or article feeds map to
WindowScroller or useWindowScroller.
- Semantic tables map to
useDynamicScroller or useRecycleScroller with flowMode, plus useTableColumnWidths to lock columns after measurement.
- Custom design-system row components map to the headless helpers.
Scope limits
This skill intentionally focuses on documented public surfaces:
- setup and installation
RecycleScroller
DynamicScroller
DynamicScrollerItem
WindowScroller
useRecycleScroller
useDynamicScroller
useWindowScroller
useTableColumnWidths
Do not infer undocumented behavior for these exported surfaces without updating docs first:
useIdState
useDynamicScrollerItem
- plugin install options beyond the documented setup path
References
Further reading
1---2name: vue-virtual-scroller3description: Use this skill for Vue 3 virtual scrolling with vue-virtual-scroller, important for good performance with a lot of data, including RecycleScroller, DynamicScroller, DynamicScrollerItem, WindowScroller, useRecycleScroller, useDynamicScroller, and useWindowScroller for fixed-size lists, unknown-size rows, grids, chat feeds, tables, and page-scrolling layouts.4---56# Vue Virtual Scroller78Use this skill when a task involves large Vue lists, DOM reuse, windowed rendering, or choosing between `RecycleScroller`, `DynamicScroller`, `WindowScroller`, and the headless helpers.910## Quick choice1112| Surface | Use it when | Avoid it when |13|---|---|---|14| `RecycleScroller` | Item size is fixed, precomputed, or available from a numeric field or resolver. | The DOM must measure unknown item size after render. |15| `DynamicScroller` | Item size is unknown before render and should be measured automatically. | A fixed-size or pre-sized path already works. |16| `DynamicScrollerItem` | You are rendering children inside `DynamicScroller` and the wrapper fits the markup. | You need wrapper-free semantics such as table rows. |17| `WindowScroller` | The browser window should drive scrolling for the component path. | The list should own its own scroll container. |18| `useRecycleScroller` | You need the virtualization engine with custom markup for known-size or pre-sized items. | The slot-based components already fit the UI. |19| `useDynamicScroller` | You need wrapper-free unknown-size measurement with custom markup or semantic table rows. | `DynamicScroller` plus `DynamicScrollerItem` already fits the UI. |20| `useWindowScroller` | The page should keep scrolling, but you still need headless control over markup and wrappers. | An inner scroll container is acceptable. |2122## Setup2324`vue-virtual-scroller` targets Vue 3, ships ESM only, and requires Vue 3.3+ for the generic component typing surface. Use it with an ESM-aware toolchain such as Vite, Nuxt, Rollup, or webpack 5.2526```sh27pnpm add vue-virtual-scroller28```2930Always import the package CSS:3132```js33import 'vue-virtual-scroller/index.css'34```3536Install all bundled components:3738```js39import { createApp } from 'vue'40import VueVirtualScroller from 'vue-virtual-scroller'4142const app = createApp(App)43app.use(VueVirtualScroller)44```4546Or register/import only what you need:4748```js49import { RecycleScroller, WindowScroller } from 'vue-virtual-scroller'5051app.component('RecycleScroller', RecycleScroller)52app.component('WindowScroller', WindowScroller)53```5455## Workflow56571. Decide whether sizes are known before render.582. If sizes are fixed or already stored in data, start with `RecycleScroller` or `useRecycleScroller`.593. If sizes are unknown until the DOM renders, use `DynamicScroller` or `useDynamicScroller`.604. If the page owns scrolling, prefer `WindowScroller` or `useWindowScroller`.615. Set explicit scroll sizing, item sizing, and keying before debugging performance.6263## Sizing rules6465- The scrolling surface must have real dimensions. Inner-scroll paths need a sized container plus overflow.66- `RecycleScroller` supports fixed numeric `itemSize`, `itemSize: null` with `sizeField`, or an `itemSize(item, index)` resolver.67- `DynamicScroller` and `useDynamicScroller` require `minItemSize` for initial layout.68- `gridItems` only works with fixed numeric `itemSize`.69- Horizontal lists follow the same rules, but sizing applies on width instead of height.70- `flowMode` is a vertical single-axis native-flow path. Use spacer elements from `startSpacerSize` and `endSpacerSize` instead of an absolutely positioned inner wrapper.7172## Practical guidance7374### Fixed-size vs unknown-size7576- Prefer `RecycleScroller` for tables, simple rows, grids, and card lists where size is stable or already known in memory.77- Use `DynamicScroller` for message feeds, cards, or rows whose rendered content changes height after filtering, editing, or streaming.78- Use headless helpers when the bundled wrapper markup gets in the way of semantics or design-system constraints.7980### Component vs headless8182- Stay on component APIs when the default slot structure already fits the UI.83- Move to `useRecycleScroller` for custom markup with known sizes.84- Move to `useDynamicScroller` for wrapper-free measurement, especially semantic tables and custom row shells.85- Move to `useWindowScroller` when page scrolling is intentional and wrapper control still matters.8687### Rendering pitfalls8889- Reused views mean child components must react when `item` changes; do not assume a fresh instance per row.90- Render from `pool`, not `visiblePool`, on headless paths when you want normal recycling behavior.91- Only reach for `watchData` when a legacy no-`ResizeObserver` fallback matters.92- On headless dynamic paths, render from `view.item`. Reach for `view.itemWithSize` only when you need measured metadata.93- Key nested images, but do not add unnecessary keys to the immediate recycled content.9495### Performance guardrails9697- `emitUpdate`, `emitResize`, and `watchData` add work; keep them off unless the UI needs them.98- Variable-size mode in `RecycleScroller` is heavier than fixed-size mode.99- `DynamicScroller` is heavier than fixed-size virtualization, so use it only when measurement is necessary.100- Browsers still impose large-element limits, so extremely large lists can hit practical ceilings.101102### Common layouts103104- Chat feeds and append-heavy timelines map well to `DynamicScroller` or `useDynamicScroller`.105- Multi-column card galleries map to `RecycleScroller` grid mode.106- Page-level search results or article feeds map to `WindowScroller` or `useWindowScroller`.107- Semantic tables map to `useDynamicScroller` or `useRecycleScroller` with `flowMode`, plus `useTableColumnWidths` to lock columns after measurement.108- Custom design-system row components map to the headless helpers.109110## Scope limits111112This skill intentionally focuses on documented public surfaces:113114- setup and installation115- `RecycleScroller`116- `DynamicScroller`117- `DynamicScrollerItem`118- `WindowScroller`119- `useRecycleScroller`120- `useDynamicScroller`121- `useWindowScroller`122- `useTableColumnWidths`123124Do not infer undocumented behavior for these exported surfaces without updating docs first:125126- `useIdState`127- `useDynamicScrollerItem`128- plugin install options beyond the documented setup path129130## References131132| Topic | Description | Reference |133|---|---|---|134| Installation and setup | Vue 3.3+, ESM-only setup, CSS import, and registration paths. | [references/installation-and-setup.md](./references/installation-and-setup.md) |135| RecycleScroller | Fixed-size and pre-sized virtualization, grids, cache restore, and older page mode. | [references/recycle-scroller.md](./references/recycle-scroller.md) |136| DynamicScroller | Unknown-size component path that measures items after render. | [references/dynamic-scroller.md](./references/dynamic-scroller.md) |137| DynamicScrollerItem | Measurement wrapper used inside `DynamicScroller`. | [references/dynamic-scroller-item.md](./references/dynamic-scroller-item.md) |138| WindowScroller | Window-based component path for page scrolling. | [references/window-scroller.md](./references/window-scroller.md) |139| useRecycleScroller | Headless fixed-size and pre-sized virtualization. | [references/use-recycle-scroller.md](./references/use-recycle-scroller.md) |140| useDynamicScroller | Headless unknown-size virtualization with wrapper-free measurement. | [references/use-dynamic-scroller.md](./references/use-dynamic-scroller.md) |141| useWindowScroller | Headless window-based virtualization. | [references/use-window-scroller.md](./references/use-window-scroller.md) |142| useTableColumnWidths | Semantic table helper that locks measured column widths. | [references/use-table-column-widths.md](./references/use-table-column-widths.md) |143| Reference index | Overview of all shipped references. | [references/index.md](./references/index.md) |144145## Further reading146147- [references/installation-and-setup.md](./references/installation-and-setup.md)148- [references/recycle-scroller.md](./references/recycle-scroller.md)149- [references/dynamic-scroller.md](./references/dynamic-scroller.md)150- [references/dynamic-scroller-item.md](./references/dynamic-scroller-item.md)151- [references/window-scroller.md](./references/window-scroller.md)152- [references/use-recycle-scroller.md](./references/use-recycle-scroller.md)153- [references/use-dynamic-scroller.md](./references/use-dynamic-scroller.md)154- [references/use-window-scroller.md](./references/use-window-scroller.md)155- [references/use-table-column-widths.md](./references/use-table-column-widths.md)