Boost PrimeNG DataTable Performance with Virtual Scrolling
Learn how to enable PrimeNG DataTable virtual scrolling to keep DOM size constant and improve scroll performance with large datasets.
14 May 2026, 06:21 UTC

Problem: UI lag when rendering thousands of rows
When a PrimeNG p-table is bound to a large array (e.g., 50 000 objects), Angular creates a DOM element for every row. The browser must layout, paint and handle events for all those elements, which leads to choppy scrolling, high memory consumption and CPU spikes.
Thesis: Virtual scrolling limits DOM nodes to the visible viewport
Enabling the virtualScroll input on p-table tells PrimeNG to render only the rows that intersect the current scroll area plus a small buffer. As the user scrolls, rows are recycled, keeping the total element count roughly constant regardless of dataset size.
Worked example: Adding virtual scrolling to a DataTable
In the component template, activate virtual scrolling and set a fixed height for the table’s scrollable area:
<p-table [value]="data" [virtualScroll]="true" [scrollHeight]="'500px'" [rows]="0"> <ng-template pTemplate="header"> <tr> <th>ID</th> <th>Name</th> <th>Value</th> </tr> </ng-template> <ng-template pTemplate="body" let-row> <tr> <td>{{row.id}}</td> <td>{{row.name}}</td> <td>{{row.value}}</td> </tr> </ng-template> </p-table>In the component class, supply a large data set. No special handling is required beyond populating the array.
import { Component, OnInit } from '@angular/core'; interface Record { id: number; name: string; value: number; } @Component({ selector: 'app-large-table', templateUrl: './large-table.component.html' }) export class LargeTableComponent implements OnInit { data: Record[] = []; ngOnInit(): void { for (let i = 0; i < 50000; i++) { this.data.push({ id: i + 1, name: `Item ${i + 1}`, value: Math.round(Math.random() * 1000) }); } } }When the table renders, inspecting the DOM shows roughly the number of rows that fit in the 500 px viewport (e.g., 20‑25 rows) plus PrimeNG’s internal buffer, regardless of the 50 000‑item source.
Trade‑off and limitation: Uniform row height assumption
Virtual scrolling calculates scroll position based on an assumed constant row height. If rows vary in height—because of wrapped text, expandable panels, or conditional styling—the scroll bar may jump or display blank spots. Features that rely on measuring row elements (e.g., custom cell templates that read offsetHeight) need to either enforce a fixed height or disable virtual scrolling for those columns.
Additionally, certain PrimeNG extensions such as column reordering, inline editing, or footer templates may require extra configuration or are not fully compatible with virtual scrolling enabled. Review the PrimeNG documentation for the specific version you are using to confirm compatibility.
Actionable closing: Verify the improvement yourself
Open Chrome DevTools → Performance tab.
Record a short scrolling session with
[virtualScroll]="false", note the average frame time.Repeat the recording with
[virtualScroll]="true"and a fixedscrollHeight.Compare the average frame times; a drop toward the 16 ms threshold (60 fps) indicates the virtual scrolling is reducing the rendering load.
In the Elements panel, expand the
p-tableand count thetrelements while scrolling. The count should stay near the viewport‑derived number plus buffer, confirming that DOM recycling is active.
If you encounter scroll jitter or blank areas, examine row heights; consider setting a explicit height on rows via CSS or disabling virtual scrolling for columns with variable content.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.