Optimizing Large Data Sets with PrimeNG p-table Virtual Scrolling
Stop browser lag when rendering thousands of rows. Learn how to implement PrimeNG virtual scrolling to keep your DOM lean and your UI responsive.
03 Jul 2025, 22:08 UTC

The Problem: DOM Bloat and UI Lag
When binding a PrimeNG p-table to a dataset containing thousands of objects, Angular generates a DOM node for every single row. This creates a massive memory footprint and forces the browser to perform expensive layout and paint operations every time the user scrolls or updates a cell. The result is a sluggish interface that often freezes during interactions.
The Solution: Virtual Scrolling
Virtual scrolling solves this by rendering only the rows currently visible in the viewport, plus a small buffer of rows above and below to ensure smooth transitions. Instead of 10,000 <tr> elements, the browser only manages a handful, regardless of the total dataset size.
Core Requirements for Implementation
For virtual scrolling to function correctly in PrimeNG, three conditions must be met:
- Explicit Height: The table must have a defined scrollable area via the
[scrollHeight]input or a CSS height on the container. Without this, the table cannot calculate the viewport boundaries. - Consistent Row Height: The engine relies on a uniform row height to calculate the offset of the scrollbar and the index of the rows to render.
- Activation: The
[virtualScroll]property must be set totrue.
Worked Example: Rendering 50,000 Rows
This example demonstrates a client-side implementation where a large array is virtualized to maintain 60fps scrolling.
1. Component Logic
In your TypeScript file, generate a large dataset to test the performance boundaries.
import { Component } from '@angular/core';
interface Product {
id: number;
name: string;
price: number;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
products: Product[] = [];
constructor() {
// Generate 50,000 records
this.products = Array.from({ length: 50000 }, (_, i) => ({
id: i,
name: `Product ${i}`,
price: Math.floor(Math.random() * 1000)
}));
}
}
2. Table Template
Configure the p-table with virtual scrolling enabled and a fixed scroll height.
<p-table
[value]="products"
[virtualScroll]="true"
[scrollHeight]="'500px'"
[rows]="20">
<ng-template pTemplate="header">
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-product>
<tr>
<td>{{product.id}}</td>
<td>{{product.name}}</td>
<td>{{product.price}}</td>
</tr>
</ng-template>
</p-table>
3. Enforcing Uniform Row Height
To prevent "jumping" during scrolls, use CSS to lock the row height.
/* Ensure cells do not wrap and maintain a strict height */
:host ::ng-deep .p-datatable-tbody td {
height: 40px;
line-height: 40px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
Verification and Diagnostics
To verify that virtual scrolling is actually working (and not just rendering everything), perform the following check:
- Run the application and open the Browser DevTools (F12).
- Navigate to the Elements tab and locate the
<tbody>of the table. - Count the number of
<tr>elements. Even with 50,000 items in the array, you should see only a small number (e.g., 15–25 rows). - Scroll rapidly. The number of
<tr>elements should remain constant as the table recycles the DOM nodes.
Trade-offs and Limitations
- Variable Row Heights: If your content varies in height (e.g., some rows have three lines of text and others have one), the virtual scroll calculations will fail. This leads to blank spaces or the scrollbar "jumping" as the engine miscalculates the total content height.
- Memory vs. DOM: While virtual scrolling reduces DOM nodes, the
[value]array still resides in JavaScript memory. For datasets exceeding 100,000 records, you should combine virtual scrolling withlazyloading to fetch data chunks from a server on demand. - Browser Support: PrimeNG uses
IntersectionObserver. If supporting very old browsers (Angular ≤ 8 era), a polyfill is required.
Actionable Summary
When dealing with large tables in PrimeNG, follow this checklist to ensure performance:
- Set
[virtualScroll]="true". - Define a specific
[scrollHeight]. - Use CSS to enforce a strict, uniform height for
tdelements. - Verify the DOM node count in DevTools to ensure virtualization is active.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.