Loading...
Loading...
Build virtualized lists, grids, and tables with react-virtuoso. Use this skill when (1) rendering large or infinite lists, (2) building grouped lists with sticky headers, (3) virtualizing HTML tables, (4) laying out same-sized items in a responsive grid, (5) building feeds or logs that follow new items at the bottom, (6) diagnosing virtualization symptoms such as jumpy scrolling, a list that does not scroll to the bottom, items overlapping, blank items, or "zero-sized element" errors, or (7) any task involving Virtuoso, GroupedVirtuoso, VirtuosoGrid, TableVirtuoso, VirtuosoHandle, itemContent, followOutput, or firstItemIndex.
npx skill4agent add virtuoso-dev/skills react-virtuosoreact-virtuosoimport { Virtuoso } from 'react-virtuoso'
;<Virtuoso style={{ height: '100%' }} data={users} itemContent={(index, user) => <div>{user.name}</div>} />| Need | Use |
|---|---|
| Flat list, variable or fixed item heights | |
| Groups with sticky group headers | |
| HTML table with virtualized rows | |
| Table with grouped rows and sticky group headers | |
| Same-sized items in a responsive multi-column grid | |
| Chat / AI conversation UI (streaming, stick-to-bottom, prepend history) | |
| Data grid with columns, sorting, filtering, column features | |
datatotalCountitemContentcomponentsestimateSizemeasureElementdata-indextransform: translateYitemSizefixedItemHeightdatatotalCountitemContentstyle={{ height: '100%' }}contentRect<p><ul><blockquote><pre>datatotalCountdataitemContent={(index, item) => ...}totalCountcomputeItemKey={(index, item) => item.id}componentsScrollerListref<Virtuoso data={items} endReached={() => loadMore()} itemContent={(index, item) => <Item item={item} />} />endReachedcomponents.FooterFooterfirstItemIndexconst [firstItemIndex, setFirstItemIndex] = useState(START)
const prepend = async () => {
const older = await fetchOlderItems()
setFirstItemIndex((i) => i - older.length)
setItems((current) => [...older, ...current])
}
<Virtuoso
computeItemKey={(_, item) => item.id}
data={items}
firstItemIndex={firstItemIndex}
initialTopMostItemIndex={{ index: 'LAST' }}
startReached={() => void prepend()}
...
/>firstItemIndex100000GroupedVirtuoso<Virtuoso followOutput="smooth" data={messages} ... />followOutput'auto' | 'smooth' | false(isAtBottom) => ...@virtuoso.dev/message-listconst ref = useRef<VirtuosoHandle>(null)
ref.current?.scrollToIndex({ index: 500, align: 'center', behavior: 'smooth' })scrollIntoViewscrollToscrollBygetStaterestoreStateFrominitialTopMostItemIndex={{ index, align: 'start' }}initialScrollTop<GroupedVirtuoso
groupCounts={[20, 30]} // items per group, in order
groupContent={(groupIndex) => <Header group={groups[groupIndex]} />}
itemContent={(index, groupIndex) => <Item item={items[index]} />} // index is absolute across all items
/>groupCounts<TableVirtuoso
data={rows}
fixedHeaderContent={() => (
<tr>
<th>Name</th>
</tr>
)}
itemContent={(index, row) => (
<>
<td>{row.name}</td>
</>
)} // <td> cells only — the row <tr> is rendered for you
/>border-collapse: collapseborder-collapse: separatecomponentsTableTableRowTableHeadTableBodyVirtuosoGridcomponents.Item33%components.Listdisplay: flex; flex-wrap: wrapuseWindowScrollcustomScrollParent={element}render(<Virtuoso data={data} />, {
wrapper: ({ children }) => (
<VirtuosoMockContext.Provider value={{ viewportHeight: 300, itemHeight: 100 }}>{children}</VirtuosoMockContext.Provider>
),
})VirtuosoGridMockContextviewportWidthitemWidth| Symptom | Likely cause | Fix |
|---|---|---|
| Nothing renders | Container has zero height | Give the component or its parent a real height |
| Cannot scroll to the last items / jumps near the bottom | Margins on item content | Replace margins with padding |
| Items flicker or lose state while scrolling | Inline | Hoist components; add |
| List jumps on prepend | Items added without | Use the |
| "zero-sized element, this should not happen" | An item rendered with zero height | Filter empty items from the data |
| "ResizeObserver loop completed with undelivered notifications" overlay in dev | Benign ResizeObserver timing, surfaced by the dev-server overlay | Disable |
| Hard-to-explain size behavior | — | Set |
increaseViewportBydefaultItemHeightfixedItemHeightscrollSeekConfigurationreferences/1.virtuoso/references/2.grouped-virtuoso/references/3.virtuoso-grid/references/4.table-virtuoso/references/5.third-party-integration/