react-virt-list
v1.0.0
Published
A high-performance virtualized list component for React — zero-config, theme-agnostic
Downloads
103
Maintainers
Readme
react-virt-list
A high-performance virtualized list for React. Renders only visible items with smooth scrolling, sticky headers, and automatic item measurement.
What it does
Drop-in virtualized list that only renders what's on screen:
- Fixed or dynamic item heights — set a fixed
itemHeight, providegetItemHeight, or let the component auto-measure - Horizontal & vertical — works in both orientations
- Inverted mode — for chat-style bottom-to-top lists
- Sticky headers — pin items at the top of the viewport
- Infinite scroll —
onEndReachedfires near the bottom - Window scroll — attach to the page scroll instead of a container
- Fast-scroll skeleton — shows placeholders during high-velocity scrolling
- Imperative API —
scrollToIndexwith start/center/end alignment - Zero-config CSS — prefixed class names (
rflv-*), no bundler config needed - Color agnostic — all colors are CSS custom properties, fits any theme
Install
npm install react-virt-listUsage
import { VirtList } from 'react-virt-list'
import 'react-virt-list/styles.css'
function App() {
const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, label: `Item ${i}` }))
return (
<VirtList
data={items}
renderItem={(item) => <div>{item.label}</div>}
keyExtractor={(item) => String(item.id)}
itemHeight={50}
/>
)
}Dynamic heights (auto-measured)
<VirtList
data={items}
renderItem={(item) => <div>{item.label}</div>}
keyExtractor={(item) => String(item.id)}
estimatedItemHeight={60}
/>Imperative scroll
import { useRef } from 'react'
import { VirtList, type VirtListHandle } from 'react-virt-list'
function App() {
const listRef = useRef<VirtListHandle>(null)
return (
<>
<button onClick={() => listRef.current?.scrollToIndex(500, 'center')}>
Go to 500
</button>
<VirtList ref={listRef} data={items} renderItem={renderItem} keyExtractor={keyExtractor} itemHeight={50} />
</>
)
}Theming (CSS custom properties)
All visual colors are exposed as CSS variables so the component works with any theme out of the box:
:root {
--flatlist-sticky-bg: #0a0a0a;
--flatlist-skeleton-bg: linear-gradient(90deg, #1a1a1a 25%, #222 50%, #1a1a1a 75%);
--flatlist-skeleton-border: #1e1e1e;
}Requirements
- React 18+
- Any bundler (Vite, webpack, Next.js, Astro, etc.)
API
<VirtList<T>>
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| data | T[] | — | The array of items to render |
| renderItem | (item: T, index: number) => ReactNode | — | Render function for each item |
| keyExtractor | (item: T, index: number) => string | — | Unique key for each item |
| itemHeight | number | — | Fixed height for all items |
| getItemHeight | (index: number) => number | — | Per-item height function |
| estimatedItemHeight | number | 40 | Estimated height for auto-measured items |
| overscan | number | 10 | Extra items to render above/below viewport |
| onEndReached | () => void | — | Fires when scroll nears the end |
| onEndReachedThreshold | number | 0.8 | Distance from end as viewport ratio |
| onScroll | (scrollPos, scrollSize, viewSize) => void | — | Scroll position callback |
| onViewableItemsChanged | (startIndex, endIndex) => void | — | Visible range callback |
| inverted | boolean | false | Reverse scroll direction (chat style) |
| horizontal | boolean | false | Horizontal scroll mode |
| initialScrollIndex | number | — | Scroll to this index on mount |
| ListEmptyComponent | ReactNode | — | Shown when data is empty |
| ListHeaderComponent | ReactNode | — | Fixed header above the list |
| ListFooterComponent | ReactNode | — | Fixed footer below the list |
| stickyHeaderIndices | number[] | — | Indices to pin as sticky headers |
| useWindowScroll | boolean | false | Use the page scroll instead of container |
| recycleItems | boolean | false | Reuse DOM nodes for performance |
| className | string | — | Additional CSS class on the container |
| style | CSSProperties | — | Inline styles on the container |
VirtListHandle
type VirtListHandle = {
scrollToIndex: (index: number, align?: 'start' | 'center' | 'end') => void
}CSS Custom Properties
| Variable | Default | Description |
| --- | --- | --- |
| --flatlist-sticky-bg | transparent | Background of sticky header overlay |
| --flatlist-skeleton-bg | light grey gradient | Skeleton placeholder gradient |
| --flatlist-skeleton-border | #d0d0d0 | Skeleton bottom border |
Exported types
import type { VirtListProps, VirtListHandle } from 'react-virt-list'License
MIT — Frederic Denis (billywild87)
