Mat-Table Add Sticky on Dynamic Columns in Angular

Angular Material Table provides a feature to stick or freeze columns, rows, footer and header. In this guide, you will learn how to add sticky properties on dynamically created columns.

This Angular post is compatible with Angular 4 upto latest versions, Angular 7, Angular 8, Angular 9, Angular 10, Angular 11, Angular 12 and Angular 13

It becomes difficult to show all columns and rows on a single screen when it contains large data sets. In such cases, we can limit the scrolling pains to much extent by freezing some of the important rows or column values.

So that even if the user scrolls around the important information doesn’t hide and is viewable all the time. This adds value to the user experience and makes data more consumable.

Let’s check implementable steps:

How to Add Sticky on Dynamic Column/ Rows in Material Table?

Follow these steps to freeze various sections of dynamically generated data table using Angular Material:

Step 1) Create Angular App

Step 2) Add Material Library and Update AppModule

Step 3) Create a Simple Material Table

Step 4) Freeze/ Stick Various Table Sections

Step 5) Update Class/ Create Generate Dynamic Data

Step 6) Update CSS Style for Sticky



Step 1) Create Angular App

To enable the ng command in the terminal window, make sure to instal the angular cli tool. If you already have, you can update it as well.

# Install NG CLI
npm install -g @angular/cli

#Update NG CLI
ng update

Afterwards, you can hit the following command to create a new angular project with the name provided:

ng new angular-material-table-app

Move inside the application folder

cd angular-material-table-app

Step 2) Add Material Library and Update AppModule

Thereafter creating and moving the terminal to the application folder, we will install the Material library by executing the ng add command. This makes the installation of the material library very easy, you can choose options while installation as shown below:

ng add @angular/material

# ? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink
# ? Set up global Angular Material typography styles? No  
# ? Set up browser animations for Angular Material? Yes

This will update the "styles" property array inside the angular.json file, which you can change anytime.

Import Material Module

The Material Library provides a huge set of usable API’s for its various modules and components. So we need to import only those modules, that we’re going to use in our application. This keeps our app more optimized and size-efficient.

Let’s import the MatTableModulefor creating Datatable.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

// Material Modules
import { MatTableModule } from '@angular/material/table';

  declarations: [AppComponent],
  imports: [BrowserModule, BrowserAnimationsModule, MatTableModule],
  providers: [],
  bootstrap: [AppComponent],
export class AppModule {}


Step 3) Create a Simple Material Table

Now head towards the HTML template to add the dynamically create table using the Mat Table components. We will be using the Material table components like mat-table, mat-row, mat-cell etc instead of Native HTML tags like table, tr, td. But you can easily replace them and use vice-versa

Open the app.component.html file and update it with the following code:

<div class="table-container" tabindex="0">
  <mat-table [dataSource]="dataSource">

    <ng-container matColumnDef="{{col}}" *ngFor="let col of displayedColumns;let i = index" [sticky]="i<3"
      [stickyEnd]="i > displayedColumns.length-3">
      <mat-header-cell *matHeaderCellDef> {{col}} </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element[col]}} </mat-cell>
      <mat-footer-cell *matFooterCellDef> <b>Footer</b> </mat-footer-cell>

    <mat-row mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
    <mat-row mat-footer-row *matFooterRowDef="displayedColumns; sticky: true"></mat-row>



Step 4) Freeze/ Stick Various Table Sections

<mat-table> component created the material data-table by taking the dataSource of rows object assigned to the [dataSource] property.

Inside the matColumnDef we used the ngFor loop to traverse all the columns defined inside the displayColumns array.

How to freeze starting columns?

The [sticky] takes boolean value to freeze or unfreaze a perticular column. We have used the column index to decide which column to make as sticky. By assignign i<3 we made first two columns at 0th and 1st position as sticky.


How to freeze end columns of datatable?

Similary the [stickyEnd] starts from end to freeze the end columns stardting from end. For [stickyEnd] we assigned i > displayColumns.length-3 to freeze last two columns of table.


How to freeze header and footer rows in datatable?

The <mat-row> with mat-header-row and mat-footer-row have the sticky:true which is making both header and footer rows as sticky. You can similarly assing any custom login to return boolean value to decide their sticky behaviour.


Step 5) Update Class/ Create Generate Dynamic Data

Now, move to the component class, that will have similar code we usually add to create datatable. We have used the for loop to dynamically create Columns and its Rows. But in real scenarios the data may code from remote services.

Update the app.component.ts file with following code:

import { Component } from '@angular/core';

  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
export class AppComponent {
  displayedColumns: any[] = [];
  dataSource: any[] = [];

  constructor() {
    // Generate columns
    for (let c = 0; c < 25; c++) {
      this.displayedColumns.push('Column_' + c);

    // Generate rows
    for (let r = 0; r < 25; r++) {
      const row: any = new Object();
      for (let c = 0; c < 25; c++) {
        row[this.displayedColumns[c]] = 'Row_' + c;


Step 6) Update CSS Style for Sticky

Most importantly you need to add the cell min-width, otherwise the mat-table sticky behaviour may not work properly. It works as expected even without min-width in case you use th native table tags.

Open the app.component.css file and following style:

.table-container {
    height: 400px;
    overflow: auto;

.mat-table-sticky {
    background: #c7ffe4;
    opacity: 1;

.mat-cell {
    min-width: 80px;
    box-sizing: border-box;

.mat-row {
    min-width: 1920px;


Step 7) See In Action

Finally, run your application by hitting the npm start command to open application at default 4200 port at following URL:



Notify of
Inline Feedbacks
View all comments