Implementing Client-Side Pagination with Angular Material MatTable
Learn how to implement client-side pagination in Angular Material using MatTableDataSource and MatPaginator, including critical lifecycle timing and performance limits.
19 Jun 2026, 11:08 UTC

Solving Table Overload with Client-Side Pagination
Loading thousands of rows into a single DOM view causes significant browser lag and degrades user experience. The most efficient way to handle moderately sized datasets (up to ~10,000 rows) in Angular Material is by pairing MatTableDataSource with the MatPaginator component. This combination allows the table to slice the data array locally, updating the view instantly without requiring new API calls.
The Integration Mechanism
To enable pagination, the MatTableDataSource must be explicitly linked to a MatPaginator instance. Because the paginator is often rendered in the template, this link must be established after the view has initialized to avoid undefined references.
Implementation Example
This example assumes Angular 15+ using standalone components. Ensure MatTableModule and MatPaginatorModule are included in your component's imports array.
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';
@Component({
selector: 'app-user-table',
standalone: true,
imports: [MatTableModule, MatPaginatorModule],
template: `
Name
{{element.name}}
`
})
export class UserTableComponent implements AfterViewInit {
displayedColumns: string[] = ['name'];
dataSource = new MatTableDataSource<any>([
{ name: 'User 1' }, { name: 'User 2' }, { name: 'User 3' },
{ name: 'User 4' }, { name: 'User 5' }, { name: 'User 6' }
]);
@ViewChild(MatPaginator) paginator!: MatPaginator;
ngAfterViewInit() {
// This link is critical for client-side pagination to function
this.dataSource.paginator = this.paginator;
}
}
Critical Configuration Details
- ViewChild Access: The
@ViewChild(MatPaginator)decorator allows the TypeScript class to reference the HTML element. - Lifecycle Timing: Assigning
this.dataSource.paginatorinsidengAfterViewInitensures the paginator element exists in the DOM before the data source attempts to bind to it. - pageSizeOptions: This input defines the available choices in the "Items per page" dropdown. If omitted, the paginator defaults to a single value.
Performance Limits and Trade-offs
Client-side pagination is a convenience feature, not a scaling solution. It is important to recognize where this approach fails:
| Metric | Client-Side (MatTableDataSource) | Server-Side (Custom DataSource) |
|---|---|---|
| Dataset Size | Best for < 10,000 rows | Unlimited / Millions of rows |
| Initial Load | Slow (fetches all data at once) | Fast (fetches only current page) |
| Memory Usage | High (browser stores full array) | Low (browser stores page slice) |
Common Implementation Mistakes
- Missing Module Imports: Forgetting
MatPaginatorModulewill result in the<mat-paginator>tag being treated as a generic HTML element, and the@ViewChildreference will remainundefined. - Binding in ngOnInit: Attempting to set
this.dataSource.paginatorinngOnInitwill fail because the template has not yet been rendered. - Data Updates: When updating the data source array (e.g., after an API refresh), you must re-assign the data to the source:
this.dataSource.data = newData;. If you push items into the existing array, the paginator may not detect the change in length.
Verification and Diagnostics
To verify the implementation is working correctly, run ng serve and perform the following checks:
- Visual Check: Ensure the paginator footer is visible and the "Items per page" dropdown correctly updates the number of rows shown.
- State Check: Open Browser DevTools and add a console log or breakpoint in the
(page)event handler of the paginator. Confirm that$event.pageIndexincrements and decrements as you navigate. - Network Check: Open the Network tab. Navigating pages should trigger zero new HTTP requests, confirming the pagination is happening locally in the browser.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.