Performancehighrendering
Virtualize long lists and tables
rule · list-virtualization
List virtualization, also called windowing, renders only the rows or cards a user can currently see plus a small buffer. This keeps large collections responsive without forcing the browser to maintain thousands of mounted nodes.
Code Examples
Render Only Visible Rows
TSX
import { FixedSizeList as List } from 'react-window'
export function OrdersList({ orders }) {
return (
<List
height={600}
itemCount={orders.length}
itemSize={56}
overscanCount={6}
width="100%"
>
{({ index, style }) => (
<div style={style}>
{orders[index].customerName}
</div>
)}
</List>
)
}Avoid Rendering Every Row
TSX
// ❌ Bad: Thousands of mounted nodes at once
export function OrdersTable({ orders }) {
return (
<table>
<tbody>
{orders.map((order) => (
<tr key={order.id}>
<td>{order.id}</td>
<td>{order.customerName}</td>
</tr>
))}
</tbody>
</table>
)
}Why It Matters
- Smaller DOM: The browser manages tens of nodes instead of thousands.
- Lower memory pressure: Mounted components, event handlers, and style data stay bounded.
- Smoother scrolling: Style recalculation, layout, and paint work stay predictable during long-list interactions.
- Better interaction performance: Selection, hover, expansion, and keyboard navigation remain responsive on dense screens.
When to Use It
Virtualization is usually worth considering when:
- A single view renders more than roughly
100-200repeated items - DOM size approaches or exceeds roughly
1,500total nodes - Scrolling shows jank, dropped frames, or slow row interactions
- Tables or dashboards hold large datasets that users inspect incrementally
Avoid it when:
- The list is small enough to render normally
- SEO or full-document find-in-page behavior requires all content to be mounted
- Accessibility semantics would be degraded by a naive windowing implementation
Standards
- Use Patterns.dev: List Virtualization as the standard for measuring the final production behavior, not just local synthetic output.
- Use web.dev: Virtualize large lists with react-window as the standard for measuring the final production behavior, not just local synthetic output.
Verification
Cross-check the result against react-window guidance on virtualized lists (opens in a new tab) so the DOM stays small without breaking keyboard or assistive-technology expectations.
- Compare the mounted node count before and after the change and confirm the view no longer renders the full dataset at once.
- Record a performance trace while scrolling and confirm layout, paint, and scripting work stay flatter with fewer long frames.
- Verify keyboard navigation, row focus, selection state, and screen-reader labels still work as expected inside the virtualized list or table.
- Tune the overscan buffer so fast scrolling does not reveal blank gaps while still keeping the mounted row count low.
- Re-test memory usage and interaction responsiveness on lower-end mobile or laptop hardware if the list is part of a critical workflow.