VirtualList
v1.0.2NewUpdated 27 Jul 2026Windowed list built on @tanstack/react-virtual that renders only the visible slice of arbitrarily long datasets while keeping list/listitem semantics, roving-tabindex keyboard navigation, and aria-setsize / aria-posinset
Preview
Live · 10 stories▸Why this is recommendedvirtualizedwindowinginfinite-scrollperformance+4
The default, out-of-the-box VirtualList.
- ✓Invoice / order registers with thousands of rows
- ✓Product or SKU pickers over large catalogs
- ✓Chat and activity logs
- ✓Infinite-loading feeds
- Renders only visible rows — 10k+ items stay fast
- Fixed or per-item estimateSize, plus dynamic measurement mode
- Grouped mode with sticky group headers
- Horizontal orientation
- Imperative scrollToIndex / scrollToOffset via ref (reduced-motion aware smooth scroll)
- onEndReached + endReachedThreshold for infinite loading with loadingFooter slot
- Empty-state slot
- Error-state slot (role="alert") with Retry — outranks empty / loading / content
- Roving-tabindex keyboard navigation (Arrows / Home / End scroll the focused row into view)
- Controlled or uncontrolled activeIndex
- aria-setsize / aria-posinset announce the true list length
- ✕Short lists under ~100 rows (use List)
- ✕Tabular data with sortable columns (use DataTable)
Install
Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.
Usage
Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.
Props
itemsFlat items (ignored when groups is set)
—groupsGrouped items with sticky headers
—renderItemRow renderer; index is the global item index
yesestimateSizeEstimated row size in px (default 44)
—dynamicMeasure rows after render for variable heights
—overscanExtra rows rendered outside the viewport (default 4)
—heightScroll viewport height (default 320)
—horizontalScroll along the x-axis
—onEndReachedInfinite-load callback fired near the end
—activeIndexControlled keyboard-active row (uncontrolled via defaultActiveIndex)
—errorError state: replaces the body with a role="alert" region (outranks empty/loading/content); true for the default localized message, or a node for a custom message + Retry
—refImperative scrollToIndex / scrollToOffset handle
—