# Virtual scrolling for lists over 100 items

- **Pattern:** `ab-002052` (`performance-deep-dive.regression-prevention.virtual-scrolling-lists`)
- **Severity:** info
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002052
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002052)

## Why it matters

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.

## Severity rationale

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.

## Remediation

Replace full-render lists with a windowing library. `react-window` (lightweight) and `@tanstack/react-virtual` (flexible) both render only visible rows.

```tsx
// 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>
  )
}
```

## Detection

- **ID:** `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.

  ```tsx
  // 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>
  ```

---

## External references

- iso-25010 performance-efficiency.resource-utilization

Taxons: performance

HTML version: https://auditbuffet.com/patterns/ab-002052
