Rendering 500 list items in the DOM simultaneously creates 500 DOM nodes with layout, paint, and event handling overhead — even for items the user cannot see. Scroll performance on a fully-rendered 10,000-row table degrades to 10–20fps on mid-range devices because every scroll event triggers layout recalculation for all 10,000 nodes. ISO 25010:2011 resource-utilisation captures the memory cost; the user-visible failure is a janky, unresponsive list that makes the application feel broken for users browsing large datasets.
Info because virtual scrolling is an optimization for large lists — its absence only matters when the list exceeds 100 items, and many applications avoid this scenario through pagination or search.
Replace full-render lists with a windowing library. react-window (lightweight) and @tanstack/react-virtual (flexible) both render only visible rows.
// components/product-list.tsx — virtual scrolling for 100+ items
import { FixedSizeList, ListChildComponentProps } from 'react-window'
function Row({ index, style }: ListChildComponentProps) {
return <div style={style}>{products[index].name}</div>
}
export function ProductList({ products }: { products: Product[] }) {
return (
<FixedSizeList
height={600}
itemCount={products.length}
itemSize={48}
width="100%"
>
{Row}
</FixedSizeList>
)
}
ID: performance-deep-dive.regression-prevention.virtual-scrolling-lists
Severity: info
What to look for: Count all list components rendering arrays. Enumerate which render over 100 items and whether they use virtual scrolling. Find list components or data tables that render many items (100+). Check whether they use virtual scrolling or windowing libraries (react-window, react-virtual, Recharts virtualization). Measure DOM node count for large lists.
Pass criteria: Lists with 100+ items use virtual scrolling. Only visible items are rendered in DOM. Scroll performance stays at 60fps.
Fail criteria: Large lists render all items in DOM, causing excessive DOM nodes and scroll jank.
Skip (N/A) when: The application has no lists with 100+ items, or all lists are paginated.
Cross-reference: For DOM node count limits, see dom-node-count-limit.
Detail on fail: "Data table with 10,000 rows renders all rows in DOM — causes 30fps scroll performance" or "No virtual scrolling detected on 500-item select dropdown"
Remediation: Implement virtual scrolling using react-window or react-virtual for large lists.
// components/data-list.tsx — virtual scrolling for 100+ items
import { FixedSizeList } from 'react-window'
<FixedSizeList height={400} itemCount={items.length} itemSize={35}>{({ index, style }) => <div style={style}>{items[index]}</div>}</FixedSizeList>