Build an Angular Admin Dashboard with Angular Material

Build an Angular Admin Dashboard with Angular Material

Build an Angular Admin Dashboard with Angular Material

A production-ready admin dashboard skeleton — the kind of UI you'd build for a CMS, analytics tool, or back-office application.

Features

  • Responsive sidenav with collapsible menu
  • Angular Material data table with sort, filter, pagination
  • Charts with ng2-charts (Chart.js wrapper)
  • Role-based route protection (admin, editor, viewer)
  • Dark/light theme toggle with Material theming
  • Lazy-loaded feature modules

Step 1 — Setup

ng new admin-dashboard --routing --style=scss
ng add @angular/material
npm install ng2-charts chart.js

Step 2 — Shell Layout Component

<!-- shell.component.html -->
<mat-sidenav-container>
  <mat-sidenav #sidenav [mode]="isHandset ? 'over' : 'side'"
               [opened]="!isHandset">
    <mat-nav-list>
      @for (item of navItems; track item.label) {
        <mat-list-item [routerLink]="item.path" routerLinkActive="active">
          <mat-icon matListItemIcon>{{ item.icon }}</mat-icon>
          <span matListItemTitle>{{ item.label }}</span>
        </mat-list-item>
      }
    </mat-nav-list>
  </mat-sidenav>

  <mat-sidenav-content>
    <mat-toolbar color="primary">
      <button mat-icon-button (click)="sidenav.toggle()">
        <mat-icon>menu</mat-icon>
      </button>
      <span>Admin Dashboard</span>
      <span class="spacer"></span>
      <button mat-icon-button (click)="toggleTheme()">
        <mat-icon>{{ isDark() ? 'light_mode' : 'dark_mode' }}</mat-icon>
      </button>
    </mat-toolbar>
    <router-outlet />
  </mat-sidenav-content>
</mat-sidenav-container>

Step 3 — Material Data Table

@Component({
  standalone: true,
  imports: [MatTableModule, MatSortModule, MatPaginatorModule, MatInputModule],
  template: `
    <mat-form-field>
      <input matInput (keyup)="applyFilter($event)" placeholder="Search" />
    </mat-form-field>

    <table mat-table [dataSource]="dataSource" matSort>
      <ng-container matColumnDef="name">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
        <td mat-cell *matCellDef="let row">{{ row.name }}</td>
      </ng-container>
      <!-- more columns... -->
      <tr mat-header-row *matHeaderRowDef="columns"></tr>
      <tr mat-row *matRowDef="let row; columns: columns"></tr>
    </table>
    <mat-paginator [pageSizeOptions]="[10, 25, 50]" />
  `,
})
export class UsersTableComponent implements AfterViewInit {
  @ViewChild(MatSort)      sort!:      MatSort;
  @ViewChild(MatPaginator) paginator!: MatPaginator;

  columns    = ['name', 'email', 'role', 'actions'];
  dataSource = new MatTableDataSource<User>();

  ngAfterViewInit(): void {
    this.dataSource.sort      = this.sort;
    this.dataSource.paginator = this.paginator;
  }

  applyFilter(event: Event): void {
    this.dataSource.filter = (event.target as HTMLInputElement).value.trim().toLowerCase();
  }
}
All Comments