CtrlK
BlogDocsLog inGet started
Tessl Logo

with-tanstack-virtual

Virtualize Vue Table final row or column models with reactive counts and scroll targets, stable keys, measurement, spacer geometry, sticky CSS, grid/flex widths, and infinite server data.

48

Quality

53%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./packages/vue-table/skills/with-tanstack-virtual/SKILL.md
SKILL.md
Quality
Evals
Security

This skill builds on @tanstack/table-core#core, getting-started, and table-state. Virtual consumes final Table models; it is not registered in tableFeatures.

Setup

import { computed, ref } from 'vue'
import { useVirtualizer } from '@tanstack/vue-virtual'

const scrollElement = ref<HTMLElement | null>(null)
const rows = computed(() => table.getRowModel().rows)
const rowVirtualizer = useVirtualizer(
  computed(() => ({
    count: rows.value.length,
    getScrollElement: () => scrollElement.value,
    estimateSize: () => 34,
    getItemKey: (index) => rows.value[index]!.id,
    overscan: 5,
  })),
)
const virtualRows = computed(() => rowVirtualizer.value.getVirtualItems())
const totalSize = computed(() => rowVirtualizer.value.getTotalSize())

Core Patterns

Derive from current visible models

Rows come from table.getRowModel().rows; columns come from table.getVisibleLeafColumns(). Use computed options so counts and scroll targets update.

Implement the geometry

Give the scroll container a bounded height and positioning context, create a spacer using getTotalSize(), and translate/measure virtual items. Follow the grid/flex examples for dynamic row heights and sticky headers.

Coordinate infinite fetching

Fetch near the last virtual item only while totalFetched < serverRowCount and no request is active. Manual sorting means the server must return the sorted order and a sort change normally resets pages.

Common Mistakes

HIGH Passing a plain options snapshot

Wrong:

useVirtualizer({ count: rows.value.length, getScrollElement })

Correct:

useVirtualizer(computed(() => ({ count: rows.value.length, getScrollElement })))

Computed options keep the virtual range synchronized with Vue’s current model.

Source: examples/vue/virtualized-rows/src/App.vue

HIGH Virtualizing source arrays

Wrong:

const rows = computed(() => data.value)

Correct:

const rows = computed(() => table.getRowModel().rows)

Source arrays do not represent Table’s current filtering, sorting, expansion, or pagination.

Source: docs/framework/vue/guide/virtualization.md

HIGH Assuming Virtual provides CSS

Wrong:

<div v-for="item in virtualRows" :key="item.key">{{ rows[item.index].id }}</div>

Correct:

<div :style="{ height: `${totalSize}px`, position: 'relative' }"><div style="position:absolute"></div></div>

Virtual provides measurements, not spacer layout, transforms, sticky positioning, or Table column widths.

Source: examples/vue/virtualized-columns/src/App.vue

API Discovery

Inspect installed @tanstack/vue-table/dist/ and @tanstack/vue-virtual/dist/; use the maintained Vue examples for exact row, column, and infinite layout combinations.

Repository
TanStack/table
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.