Virtualize only the visible content for massive scrollable DOM nodes at 60FPS in TS/JS, React, Vue, Solid, Svelte, Lit & Angular while retaining 100% control over markup and styles.
Get Startedimport { useVirtualizer } from '@tanstack/react-virtual'
const rowVirtualizer = useVirtualizer({
count: 1000,
getScrollElement: () => parentRef.current,
estimateSize: () => 36,
})
// Map virtual rows to your UIimport { useVirtualizer } from '@tanstack/react-virtual'
const rowVirtualizer = useVirtualizer({
count: 1000,
getScrollElement: () => parentRef.current,
estimateSize: () => 36,
})
// Map virtual rows to your UIimport { createVirtualizer } from '@tanstack/solid-virtual'
const parentRef: HTMLElement | undefined = undefined
const rowVirtualizer = createVirtualizer({
count: 1000,
getScrollElement: () => parentRef!,
estimateSize: () => 36,
})
// Map rowVirtualizer.getVirtualItems() to your UIimport { createVirtualizer } from '@tanstack/solid-virtual'
const parentRef: HTMLElement | undefined = undefined
const rowVirtualizer = createVirtualizer({
count: 1000,
getScrollElement: () => parentRef!,
estimateSize: () => 36,
})
// Map rowVirtualizer.getVirtualItems() to your UI<script setup lang="ts">
import { ref } from 'vue'
import { useVirtualizer } from '@tanstack/vue-virtual'
const parentRef = ref<HTMLElement | null>(null)
const rowVirtualizer = useVirtualizer({
count: 1000,
getScrollElement: () => parentRef.value!,
estimateSize: () => 36,
})
</script>
<template>
<div ref="parentRef" style="overflow: auto; height: 300px">
<!-- Render rowVirtualizer.getVirtualItems() -->
</div>
</template><script setup lang="ts">
import { ref } from 'vue'
import { useVirtualizer } from '@tanstack/vue-virtual'
const parentRef = ref<HTMLElement | null>(null)
const rowVirtualizer = useVirtualizer({
count: 1000,
getScrollElement: () => parentRef.value!,
estimateSize: () => 36,
})
</script>
<template>
<div ref="parentRef" style="overflow: auto; height: 300px">
<!-- Render rowVirtualizer.getVirtualItems() -->
</div>
</template><script lang="ts">
import { createVirtualizer } from '@tanstack/svelte-virtual'
let parentRef: HTMLDivElement
const rowVirtualizer = createVirtualizer({
count: 1000,
getScrollElement: () => parentRef,
estimateSize: () => 36,
})
</script>
<div bind:this={parentRef} style="overflow:auto; height:300px">
<!-- Render $rowVirtualizer.getVirtualItems() -->
</div><script lang="ts">
import { createVirtualizer } from '@tanstack/svelte-virtual'
let parentRef: HTMLDivElement
const rowVirtualizer = createVirtualizer({
count: 1000,
getScrollElement: () => parentRef,
estimateSize: () => 36,
})
</script>
<div bind:this={parentRef} style="overflow:auto; height:300px">
<!-- Render $rowVirtualizer.getVirtualItems() -->
</div>import { LitElement, customElement, html } from 'lit'
import { createLitVirtualizer } from '@tanstack/lit-virtual'
@customElement('virtual-list')
export class VirtualList extends LitElement {
private parent?: HTMLDivElement
virtualizer = createLitVirtualizer({
count: 1000,
getScrollElement: () => this.parent!,
estimateSize: () => 36,
})
render() {
return html`<div style="overflow:auto; height:300px"></div>`
}
}import { LitElement, customElement, html } from 'lit'
import { createLitVirtualizer } from '@tanstack/lit-virtual'
@customElement('virtual-list')
export class VirtualList extends LitElement {
private parent?: HTMLDivElement
virtualizer = createLitVirtualizer({
count: 1000,
getScrollElement: () => this.parent!,
estimateSize: () => 36,
})
render() {
return html`<div style="overflow:auto; height:300px"></div>`
}
}import { Component, ElementRef, viewChild } from '@angular/core'
import { createAngularVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'virtual-list',
template: '<div #parent style="overflow:auto; height:300px"></div>',
})
export class VirtualListComponent {
parent = viewChild.required<ElementRef<HTMLDivElement>>('parent')
virtualizer = createAngularVirtualizer(() => ({
count: 1000,
getScrollElement: () => this.parent().nativeElement,
estimateSize: () => 36,
}))
}import { Component, ElementRef, viewChild } from '@angular/core'
import { createAngularVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'virtual-list',
template: '<div #parent style="overflow:auto; height:300px"></div>',
})
export class VirtualListComponent {
parent = viewChild.required<ElementRef<HTMLDivElement>>('parent')
virtualizer = createAngularVirtualizer(() => ({
count: 1000,
getScrollElement: () => this.parent().nativeElement,
estimateSize: () => 36,
}))
}See what teams are saying
"We chose TanStack Virtual for our virtualization needs - it handles our massive lists without breaking a sweat."
"TanStack Virtual is the answer when you need to render thousands of rows without destroying performance. Headless, flexible, and just works."
"For anyone dealing with large datasets in React, TanStack Virtual is a must. The row virtualizer alone saved our app."
"We chose TanStack Virtual for our virtualization needs - it handles our massive lists without breaking a sweat."
"TanStack Virtual is the answer when you need to render thousands of rows without destroying performance. Headless, flexible, and just works."
"For anyone dealing with large datasets in React, TanStack Virtual is a must. The row virtualizer alone saved our app."
With just a few divs and some inline styles, you're already well on your way to creating an extremely powerful virtualization experience.