Angular Material Make Sticky Header and Footer

Angular Material Make Sticky Header and Footer

I'm using angular6 with Angular material design templates. currently, my result is as follows,

Currently, I have sticky header and footer but the scrolling dataset is not user-friendly. issue-data-html is my HTML file,

<div class="mainDiv">
  <div class="mat-elevation-z8 issueDataCard">
    <div style="position: relative; z-index: 1; " class="app-list-header" fxLayout="row" fxLayoutAlign="start baseline"
      fxLayoutGap="8px" fxLayoutGap.gt-xs="24px">
      <div fxLayout="column" fxLayoutAlign="start baseline" fxLayoutGap="24px" fxFlex="grow" fxLayout.gt-xs="row">
        <div class="app-list-name">
          <h3>
            Issue Statuses
          </h3>
        </div>
        <div class="vl"></div>
        <!--Search-->
        <mat-form-field class="app-filter-input" floatPlaceholder="never" fxFlex>
          <mat-icon class="app-filter-input-icon" matPrefix>search</mat-icon>
          <input matInput #filter placeholder="Search&hellip;" (keyup)="applyFilter($event.target.value)">
        </mat-form-field>
      </div>

      <div fxFlex="none">
        <button mat-mini-fab style="background-color: #281c7b;" *ngIf="showAddIssueDataIcon"
          (click)="addIssueData(null)" matTooltip="Add Issue Data">
          <mat-icon>add</mat-icon>
        </button>
      </div>

      <button class="app-column-filter" type="button" mat-icon-button [matMenuTriggerFor]="columnFilter">
        <mat-icon style="font-size: 130%; color:#929292" matTooltip="Configure Table">settings</mat-icon>
      </button>
      &nbsp;&nbsp;
      <mat-menu #columnFilter="matMenu" yPosition="below" xPosition="before">
        <button class="checkbox-item mat-menu-item" *ngFor="let column of displayedColumns"
          (click)="toggleColumnVisibility(column, $event)">
          <mat-checkbox [(ngModel)]="column.visible" (change)="columnFilterCheckboxClick($event)" class="checkbox"
            #checkbox (click)="$event.stopPropagation()">
            {{ column.name }}
          </mat-checkbox>
        </button>
      </mat-menu>
      <ng-content select=".actions"></ng-content>
    </div>

    <!--table-->
    <table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">
      <!-- issueStatus Column -->
      <ng-container matColumnDef="issueStatus">
        <th mat-sort-header="name" mat-header-cell *matHeaderCellDef>ISSUE STATUS</th>
        <td mat-cell *matCellDef="let element">
          {{element.name}}
        </td>
      </ng-container>

      <!-- showInBacklog Column -->
      <ng-container matColumnDef="showInBacklog">
        <th mat-sort-header="backlog" mat-header-cell *matHeaderCellDef>SHOW IN BACKLOG</th>
        <td mat-cell *matCellDef="let element" style="text-transform: uppercase">
          {{element.backlog}}
        </td>
      </ng-container>

      <!-- Status Column -->
      <ng-container matColumnDef="status">
        <th mat-sort-header="status" mat-header-cell *matHeaderCellDef>STATUS</th>
        <td mat-cell *matCellDef="let element" style="text-transform: uppercase">
          {{element.status}}
        </td>
      </ng-container>

      <!-- Actions Column -->
      <ng-container matColumnDef="action">
        <th mat-header-cell *matHeaderCellDef class="action-cell" style="padding-right: 40px">ACTIONS</th>
        <td mat-cell *matCellDef="let element; let i = index" class="action-cell">
          <button mat-icon-button *ngIf="showAddIssueDataIcon" (click)="editIssueData(element)">
            <mat-icon class="iconStyle" matTooltip="Edit Issue Data">edit</mat-icon>
          </button>
          &nbsp;&nbsp;
          <!--&nbsp;&nbsp;-->
          <a style="cursor: pointer" *ngIf="showEditIssue">
            <i class="material-icons" style="color:#757575" [matMenuTriggerFor]="selectMenu"
              matTooltip="More actions">more_vert</i></a>
          <mat-menu #selectMenu="matMenu">
            <button mat-menu-item *ngIf="element.status === 'INACTIVE'"
              (click)="onClickEditStatus(element , true,i)">Make Active</button>
            <button mat-menu-item *ngIf="element.status === 'ACTIVE'"
              (click)="onClickEditStatus(element , false,i)">Make Inactive</button>
            <button mat-menu-item (click)="deleteIssueData(element,i)">Delete</button>
          </mat-menu>
        </td>
      </ng-container>


      <tr mat-header-row *matHeaderRowDef="visibleColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: visibleColumns;"
        [ngClass]="{ hovered: row.hovered, highlighted: row.highlighted }" (click)="row.highlighted = !row.highlighted"
        (mouseover)="row.hovered = true" (mouseout)="row.hovered = false"></tr>
    </table>
    <mat-paginator [pageSize]="savedPageSize" (page)="columnFilterCheckboxClick($event)"
      [pageSizeOptions]="[5, 10, 20, 100]" showFirstLastButtons></mat-paginator>
  </div>

</div>

My css file is as follows,

   .issueDataCard{
    margin: 20px;
  }
  /* Structure */
  table {
    width: 100%;
  }
  .mat-sort-header-container {
    align-items: center;
  }
  .mat-form-field {
    font-size: 14px;
    width: 98%;
    margin: 10px;
  }
  @import "var";

  .app-list-name {
    color: $color;
    border-right: 1px solid $theme-divider;
    font-size: 20px;
    line-height: 0px;
    font-weight: 500;
    padding-right: $spacing;
    padding-left: $spacing;
    @include media-xs {
      border-right: none;
    }
  }

  .iconStyle{
    color:#281c7b;
    cursor: pointer;
  }
  .slideToggleStyle{
    display: flex;
    flex-direction: column;
    align-items: flex-end;
  }
  .divMarginStyle{
    margin-bottom: 20px;
    margin-right: 20px;
  }


  .dataStyle{
    text-align: center;
  }
  .dateStyle{
    color:#5D6C7F;
    font-size: 10px;
  }
  .actions{
    padding-right: 30px;
  }

  .action-cell{
    text-align: right;
  }

  .mat-cell{
    align-items: center;
  }

  .mat-elevation-z8 {
    display: flex;
    flex-direction: column;
    max-height: 500px;
    width: 100%;
    margin-bottom: 1.5%;
    overflow: auto;
  }

I have no idea how to change these CSS classes according to my need, Any help will be greatly accepted.

3 Answers

Or you can just use sticky to the tr mat-header-row. For example:

<tr mat-header-row *matHeaderRowDef="columnsToDisplay; sticky:true"></tr>

Finally hours of coding and changing CSS I found an answer to my question and I thought to post here because this will be helpful for someone in the future.

If I look at the above question I have used pure <table></table> tag for creating the table and for rows and columns I have used <th></th> and <td></td> tags. In Angular Material, there are specific tags for creating a table and assign rows and columns and furthermore to add sticky header and footer. If we won't use those tags there can be some misalignments. So finally I changed my code as below,

issue-data-component.html file is as follows,

<div class="mainDiv">
  <div class="example-container  mat-elevation-z8" style="background-color: white"
    (click)="columnFilterCheckboxClick($event)">
    <div>
      <div class="app-list-header" fxLayout="row" fxLayoutAlign="start baseline" fxLayoutGap="8px"
        fxLayoutGap.gt-xs="24px">
        <div fxLayout="column" fxLayoutAlign="start baseline" fxLayoutGap="24px" fxFlex="grow" fxLayout.gt-xs="row">
          <div class="app-list-name">
            <h3> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Issue Statuses</h3>
          </div>
          <div class="vl"></div>
          <mat-form-field class="app-filter-input" floatPlaceholder="never" fxFlex>
            <mat-icon style=" color: #999999;" class="app-filter-input-icon" matPrefix>search</mat-icon>
            <input matInput #filter placeholder="Search&hellip;" (keyup)="applyFilter($event.target.value)">
          </mat-form-field>
        </div>
        <div class="actions">
          <button mat-fab style="background-color: #281c7b;" (click)="addIssueData(null)" matTooltip="Add Issue Data"
            *ngIf="showAddIssueDataIcon">
            <mat-icon>add</mat-icon>
          </button>
        </div>
        <button class="app-column-filter" type="button" mat-icon-button [matMenuTriggerFor]="columnFilter">
          <mat-icon style="font-size: 130%; color: #929292 " matTooltip="Configure Table">settings</mat-icon>
        </button>
        <ng-content select=".actions"></ng-content>
      </div>
      <mat-menu #columnFilter="matMenu" yPosition="below" xPosition="before">
        <button class="checkbox-item mat-menu-item" *ngFor="let column of displayedColumns"
          (click)="toggleColumnVisibility(column, $event)">
          <mat-checkbox [(ngModel)]="column.visible" (change)="columnFilterCheckboxClick($event)" class="checkbox"
            #checkbox (click)="$event.stopPropagation();">
            {{ column.name }}
          </mat-checkbox>
        </button>
      </mat-menu>
      <ng-content></ng-content>
    </div>
    <mat-divider></mat-divider>
    <mat-table #table [dataSource]="dataSource" matSort class="tableStyle">
      <!-- issueStatus Column -->
      <ng-container matColumnDef="issueStatus">
        <mat-header-cell *matHeaderCellDef mat-sort-header="name" style="max-width: 35%; min-width: 35%;"> STATUS
        </mat-header-cell>
        <mat-cell *matCellDef="let element" style="max-width: 35%; min-width: 35%;">
          {{element.name}}
        </mat-cell>
      </ng-container>
      <!-- showInBacklog Column -->
      <ng-container matColumnDef="showInBacklog">
        <mat-header-cell *matHeaderCellDef mat-sort-header="backlog" style="max-width: 25%; min-width: 25%;">ISSUE
          STATUS
        </mat-header-cell>
        <mat-cell *matCellDef="let element" style="text-transform: uppercase; max-width: 25%; min-width: 25%;">
          {{element.backlog}}
        </mat-cell>
      </ng-container>
      <!-- Status Column -->
      <ng-container matColumnDef="status">
        <mat-header-cell *matHeaderCellDef mat-sort-header="status" style="max-width: 30%; min-width: 30%;"> SHOW IN
          BACKLOG </mat-header-cell>
        <mat-cell *matCellDef="let element" style="text-transform: uppercase; max-width: 30%; min-width: 30%;">
          {{element.status}}</mat-cell>
      </ng-container>

      <!-- Actions Column -->
      <ng-container matColumnDef="action">
        <mat-header-cell class="action-cell" *matHeaderCellDef style="max-width: 5%; min-width: 5%;">ACTION
        </mat-header-cell>
        <mat-cell class="action-cell" *matCellDef="let element; let i = index" style="max-width: 5%; min-width: 5%;">

          <button mat-icon-button *ngIf="showAddIssueDataIcon" (click)="editIssueData(element)">
            <mat-icon class="iconStyle" matTooltip="Edit Issue Data">edit</mat-icon>
          </button>
          &nbsp;&nbsp;
          <!--&nbsp;&nbsp;-->
          <a style="cursor: pointer" *ngIf="showEditIssue">
            <i class="material-icons" style="color:#757575" [matMenuTriggerFor]="selectMenu"
              matTooltip="More actions">more_vert</i></a>
          <mat-menu #selectMenu="matMenu">
            <button mat-menu-item *ngIf="element.status === 'INACTIVE'"
              (click)="onClickEditStatus(element , true,i)">Make Active</button>
            <button mat-menu-item *ngIf="element.status === 'ACTIVE'"
              (click)="onClickEditStatus(element , false,i)">Make Inactive</button>
            <button mat-menu-item (click)="deleteIssueData(element,i)">Delete</button>
          </mat-menu>
        </mat-cell>
      </ng-container>

      <mat-header-row *matHeaderRowDef="visibleColumns"></mat-header-row>

      <mat-row *matRowDef="let row; columns: visibleColumns;" class="clickable"></mat-row>   
    </mat-table>
    <mat-paginator [pageSize]="savedPageSize" (page)="columnFilterCheckboxClick($event)"
      [pageSizeOptions]="[5, 10, 20, 100]" showFirstLastButtons></mat-paginator>

  </div>
</div>

And I have added following CSS fields additionally to my CSS file,

.mat-elevation-z8 {
  display: flex;
  flex-direction: column;
  max-height: 500px;
  width: 95%;
   margin: 3% 3% 3% 3%;

  overflow: auto;
}

.tableStyle{
  max-height: 500px;
  overflow: auto;
 }
 mat-header-cell, mat-header-row{
  position: sticky;
  top:0;
  background: white;
 }

Now the sticky header and footer workes fine and the alignments are well aligned,

I think this will work if not please generate stackblitz of your code

table {
  width: 100%;
}
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Alexander Ross
Author

Alexander Ross

Alexander Ross has covered the video game industry for a decade, writing deep dives on game design, esports tournaments, VR developments, and gaming culture.