Each DOM node has a memory and layout cost. A page with 3,000+ nodes triggers slower style recalculations, longer layout passes, and higher memory usage — all of which degrade scrolling smoothness and interaction responsiveness. ISO 25010:2011 resource-utilisation quantifies the overhead; the practical failure mode is a data table that renders 5,000 rows at once, consuming hundreds of megabytes of memory and making the page unusable on mid-range devices.
Medium because excessive DOM nodes slow layout recalculation and increase memory consumption, causing scroll jank and interaction lag that scales with the number of nodes beyond the 1,500 threshold.
Replace full-render lists with a virtualizer that renders only the rows currently in the viewport. @tanstack/react-virtual is a solid zero-dependency option.
// components/data-table.tsx
import { useVirtualizer } from '@tanstack/react-virtual'
const virtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => containerRef.current,
estimateSize: () => 40,
})
return (
<div ref={containerRef} style={{ height: '500px', overflow: 'auto' }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualizer.getVirtualItems().map((vr) => (
<div key={vr.key} style={{ position: 'absolute', top: vr.start }}>
{rows[vr.index]}
</div>
))}
</div>
</div>
)
ID: performance-deep-dive.runtime-memory.dom-node-count-limit
Severity: medium
What to look for: Count all list-rendering components that could produce over 100 DOM nodes. Enumerate which use virtual scrolling vs. rendering all items. Open Chrome DevTools → Elements tab. Count DOM nodes on a typical page. For pages with lists, check node count after rendering a full list vs. after implementing virtual scrolling.
Pass criteria: Typical pages have under 1500 DOM nodes. Pages with large data tables use virtual scrolling to limit DOM size.
Fail criteria: Typical page has over 1500 DOM nodes, or a data table with 1000+ items renders all items in DOM.
Skip (N/A) when: Never — DOM bloat affects all pages.
Cross-reference: For virtual scrolling implementation, see virtual-scrolling-lists in Regression Prevention.
Detail on fail: "Dashboard page has 3200 DOM nodes — each widget renders full child tree" or "Data table with 5000 rows renders all 5000 in DOM. No virtual scrolling"
Remediation: Use virtual scrolling for long lists and data tables using libraries like react-virtual or react-window.
// components/data-table.tsx — virtual scrolling
import { useVirtualizer } from '@tanstack/react-virtual'
const virtualizer = useVirtualizer({ count: items.length, getScrollElement: () => parentRef.current, estimateSize: () => 35 })