angular-material
SKILL.md
Angular Material Component Library Skill
Rules
Setup and Configuration
- Must install
@angular/material,@angular/cdk,@angular/animations - Must configure
provideAnimations()inapp.config.ts - Must import specific Material modules (e.g.,
MatButtonModule,MatIconModule) - Must NOT import all Material modules with wildcard (
import * as Material)
Form Controls
- Must wrap all
matInputin<mat-form-field>with<mat-label> - Must use
appearance="outline"orappearance="fill"for form fields - Must use Reactive Forms with Material form controls
- Must provide validation error messages with
<mat-error> - Must use
MatDatepickerModulewithMatNativeDateModulefor date pickers
Navigation Components
- Must set explicit height on
<mat-sidenav-container> - Must use
mat-nav-listfor navigation lists with@forandtrack - Must use
colorattribute for semantic styling (primary,accent,warn)
Buttons and Icons
- Must use appropriate button variant:
mat-button,mat-raised-button,mat-flat-button,mat-stroked-button,mat-icon-button,mat-fab,mat-mini-fab - Must provide
aria-labelfor icon-only buttons - Must import Material Icons font in
index.html
Data Tables
- Must define
displayedColumnsfor table columns - Must use
matColumnDef,mat-header-cell,mat-cellfor column definition - Must use
MatSortdirective withmat-sort-headerfor sorting - Must set
dataSource.sortanddataSource.paginatorinngAfterViewInit() - Must use
MatPaginatorwith[pageSize]and[pageSizeOptions]
Dialogs and Popups
- Must inject
MatDialogservice to open dialogs - Must use
<h2 mat-dialog-title>,<mat-dialog-content>,<mat-dialog-actions>structure - Must use
[mat-dialog-close]for dialog action buttons - Must configure dialog width in open options
- Must subscribe to
afterClosed()for dialog results
Theming
- Must use
@use '@angular/material' as matin SCSS - Must define custom palettes with
mat.define-palette() - Must create theme with
mat.define-light-theme()ormat.define-dark-theme() - Must include
@include mat.all-component-themes($theme)
Accessibility
- Must provide labels for all form fields
- Must add ARIA attributes for icon-only buttons
- Must ensure keyboard navigation support
- Must use semantic color attributes (
primary,accent,warn)
Performance
- Must import only needed Material modules
- Must use
@deferfor lazy loading heavy components - Must use virtual scrolling for large lists
Context
Summary
Angular Material is the official Material Design component library for Angular, providing 50+ production-ready components with built-in accessibility, theming, and TypeScript support.
When to Use This Skill
- Building Angular applications with Material Design
- Implementing forms with Material form controls
- Creating data tables with sorting, pagination, and filtering
- Building navigation with Material sidenav and toolbars
- Implementing dialogs, snackbars, and bottom sheets
- Using Material icons and buttons
- Creating custom themes
- Ensuring accessibility compliance
Installation
# Using Angular CLI (recommended)
ng add @angular/material
# Or using npm/pnpm
pnpm install @angular/material @angular/cdk @angular/animations
Application Setup
// app.config.ts (Angular 20+ standalone)
import { provideAnimations } from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [
provideAnimations(),
// ... other providers
]
};
Component Import Example
// In standalone component
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatToolbarModule } from '@angular/material/toolbar';
@Component({
selector: 'app-header',
standalone: true,
imports: [MatButtonModule, MatIconModule, MatToolbarModule],
template: `
<mat-toolbar color="primary">
<span>My App</span>
<span class="spacer"></span>
<button mat-icon-button>
<mat-icon>menu</mat-icon>
</button>
</mat-toolbar>
`
})
export class HeaderComponent {}
📚 Core Component Categories
1. Form Controls
Input & Text Fields:
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
@Component({
standalone: true,
imports: [MatFormFieldModule, MatInputModule, ReactiveFormsModule],
template: `
<mat-form-field appearance="outline">
<mat-label>Email</mat-label>
<input matInput [formControl]="email" placeholder="user@example.com">
<mat-hint>Enter your email address</mat-hint>
@if (email.hasError('email')) {
<mat-error>Invalid email format</mat-error>
}
</mat-form-field>
`
})
export class EmailInputComponent {
email = new FormControl('', [Validators.required, Validators.email]);
}
Select & Autocomplete:
import { MatSelectModule } from '@angular/material/select';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
// Select example
<mat-form-field>
<mat-label>Country</mat-label>
<mat-select [formControl]="country">
@for (country of countries; track country.code) {
<mat-option [value]="country.code">{{ country.name }}</mat-option>
}
</mat-select>
</mat-form-field>
// Autocomplete example
<mat-form-field>
<mat-label>Search</mat-label>
<input matInput [formControl]="search" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
@for (option of filteredOptions(); track option) {
<mat-option [value]="option">{{ option }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
Checkboxes & Radio Buttons:
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatRadioModule } from '@angular/material/radio';
// Checkbox
<mat-checkbox [formControl]="agreeToTerms">
I agree to terms and conditions
</mat-checkbox>
// Radio group
<mat-radio-group [formControl]="selectedOption">
<mat-radio-button value="option1">Option 1</mat-radio-button>
<mat-radio-button value="option2">Option 2</mat-radio-button>
</mat-radio-group>
Date & Time Pickers:
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from '@angular/material/core';
<mat-form-field>
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker" [formControl]="selectedDate">
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
2. Navigation Components
Toolbar:
import { MatToolbarModule } from '@angular/material/toolbar';
<mat-toolbar color="primary">
<button mat-icon-button>
<mat-icon>menu</mat-icon>
</button>
<span>Application Title</span>
<span class="spacer"></span>
<button mat-icon-button>
<mat-icon>account_circle</mat-icon>
</button>
</mat-toolbar>
Sidenav:
import { MatSidenavModule } from '@angular/material/sidenav';
<mat-sidenav-container class="sidenav-container">
<mat-sidenav #sidenav mode="side" opened>
<mat-nav-list>
@for (item of navItems; track item.route) {
<a mat-list-item [routerLink]="item.route">
<mat-icon>{{ item.icon }}</mat-icon>
{{ item.label }}
</a>
}
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
Tabs:
import { MatTabsModule } from '@angular/material/tabs';
<mat-tab-group>
<mat-tab label="Overview">
<div class="tab-content">Overview content</div>
</mat-tab>
<mat-tab label="Details">
<div class="tab-content">Details content</div>
</mat-tab>
<mat-tab label="Settings">
<div class="tab-content">Settings content</div>
</mat-tab>
</mat-tab-group>
3. Layout Components
Cards:
import { MatCardModule } from '@angular/material/card';
<mat-card>
<mat-card-header>
<mat-card-title>Card Title</mat-card-title>
<mat-card-subtitle>Card Subtitle</mat-card-subtitle>
</mat-card-header>
<img mat-card-image src="image.jpg" alt="Photo">
<mat-card-content>
<p>Card content goes here</p>
</mat-card-content>
<mat-card-actions>
<button mat-button>LIKE</button>
<button mat-button>SHARE</button>
</mat-card-actions>
</mat-card>
Grid List:
import { MatGridListModule } from '@angular/material/grid-list';
<mat-grid-list cols="3" rowHeight="200px">
@for (tile of tiles; track tile.id) {
<mat-grid-tile [colspan]="tile.cols" [rowspan]="tile.rows">
<img [src]="tile.image" [alt]="tile.title">
<mat-grid-tile-footer>
<h3>{{ tile.title }}</h3>
</mat-grid-tile-footer>
</mat-grid-tile>
}
</mat-grid-list>
4. Buttons & Indicators
Buttons:
import { MatButtonModule } from '@angular/material/button';
<!-- Different button types -->
<button mat-button>Basic</button>
<button mat-raised-button color="primary">Raised</button>
<button mat-flat-button color="accent">Flat</button>
<button mat-stroked-button>Stroked</button>
<button mat-icon-button><mat-icon>favorite</mat-icon></button>
<button mat-fab color="primary"><mat-icon>add</mat-icon></button>
<button mat-mini-fab color="accent"><mat-icon>edit</mat-icon></button>
Progress Indicators:
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressBarModule } from '@angular/material/progress-bar';
<!-- Spinner -->
<mat-spinner></mat-spinner>
<mat-spinner diameter="50"></mat-spinner>
<!-- Progress bar -->
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
<mat-progress-bar mode="determinate" [value]="progressValue"></mat-progress-bar>
5. Popups & Modals
Dialog:
import { MatDialogModule, MatDialog } from '@angular/material/dialog';
// Open dialog
openDialog() {
const dialogRef = this.dialog.open(MyDialogComponent, {
width: '600px',
data: { name: 'User Name' }
});
dialogRef.afterClosed().subscribe(result => {
console.log('Dialog result:', result);
});
}
// Dialog component
@Component({
template: `
<h2 mat-dialog-title>Dialog Title</h2>
<mat-dialog-content>
<p>Dialog content</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>Cancel</button>
<button mat-raised-button color="primary" [mat-dialog-close]="true">
Confirm
</button>
</mat-dialog-actions>
`
})
export class MyDialogComponent {
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {}
}
Snackbar:
import { MatSnackBarModule, MatSnackBar } from '@angular/material/snackbar';
showSnackbar() {
this.snackBar.open('Message sent successfully!', 'Close', {
duration: 3000,
horizontalPosition: 'end',
verticalPosition: 'top'
});
}
Bottom Sheet:
import { MatBottomSheetModule, MatBottomSheet } from '@angular/material/bottom-sheet';
openBottomSheet() {
this.bottomSheet.open(BottomSheetComponent);
}
6. Data Tables
Table with Sorting & Pagination:
import { MatTableModule } from '@angular/material/table';
import { MatSortModule, MatSort } from '@angular/material/sort';
import { MatPaginatorModule, MatPaginator } from '@angular/material/paginator';
@Component({
template: `
<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 element">{{ element.name }}</td>
</ng-container>
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Email</th>
<td mat-cell *matCellDef="let element">{{ element.email }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 25, 100]">
</mat-paginator>
`
})
export class TableComponent implements AfterViewInit {
displayedColumns = ['name', 'email'];
dataSource = new MatTableDataSource(this.data);
@ViewChild(MatSort) sort!: MatSort;
@ViewChild(MatPaginator) paginator!: MatPaginator;
ngAfterViewInit() {
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
}
}
🎯 Best Practices
1. Import Only What You Need
// ✅ Good - Import specific modules
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
// ❌ Bad - Don't import everything
import * as Material from '@angular/material';
2. Use Appearance Variants
// Material form fields support different appearances
<mat-form-field appearance="fill"> <!-- Default -->
<mat-form-field appearance="outline"> <!-- Outlined -->
<mat-form-field appearance="legacy"> <!-- Deprecated -->
3. Leverage Color Themes
// Use color attribute for semantic styling
<button mat-raised-button color="primary">Primary</button>
<button mat-raised-button color="accent">Accent</button>
<button mat-raised-button color="warn">Warn</button>
4. Accessibility
// Always provide labels and ARIA attributes
<button mat-icon-button aria-label="Delete item">
<mat-icon>delete</mat-icon>
</button>
<mat-form-field>
<mat-label>Email</mat-label> <!-- Always include labels -->
<input matInput type="email">
</mat-form-field>
5. Responsive Design
// Use Material breakpoints
@use '@angular/material' as mat;
@media (max-width: mat.$small-breakpoint) {
.sidenav {
mode: 'over';
}
}
🔧 Theming
Custom Theme
@use '@angular/material' as mat;
$my-primary: mat.define-palette(mat.$indigo-palette);
$my-accent: mat.define-palette(mat.$pink-palette);
$my-warn: mat.define-palette(mat.$red-palette);
$my-theme: mat.define-light-theme((
color: (
primary: $my-primary,
accent: $my-accent,
warn: $my-warn,
),
typography: mat.define-typography-config(),
density: 0,
));
@include mat.all-component-themes($my-theme);
🐛 Troubleshooting
| Issue | Solution |
|---|---|
| Animations not working | Import provideAnimations() or BrowserAnimationsModule |
| Icons not showing | Import Material Icons font in index.html |
| Styles not applying | Import @angular/material/prebuilt-themes in styles.scss |
| Form field errors | Wrap input in <mat-form-field> with <mat-label> |
| Table not sorting | Add MatSort directive and set dataSource.sort |
| Dialog not opening | Inject MatDialog service and import MatDialogModule |
📖 References
- Angular Material Official Docs
- Component API Reference
- Material Design Guidelines
- Angular Material GitHub
📂 Recommended Placement
Project-level skill:
/.github/skills/angular-material/SKILL.md
Copilot will load this when working with Angular Material components.
Weekly Installs
5
Repository
7spade/black-tortoiseFirst Seen
Jan 26, 2026
Security Audits
Installed on
antigravity4
opencode2
windsurf2
claude-code2
codex2
gemini-cli2