---
name: angular-material
description: Use when working with Angular Material components, theming, or styling. Triggers on requests involving "material", "theme", "mat-", buttons, dialogs, forms, tables, or UI components.
---
# Angular Material Guide
Use Angular Material v3 components and theming following project patterns.
## Component Imports
Import Material components directly (standalone):
```typescript
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDialogModule } from '@angular/material/dialog';
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatListModule } from '@angular/material/list';
import { MatMenuModule } from '@angular/material/menu';
import { MatTabsModule } from '@angular/material/tabs';
import { MatChipsModule } from '@angular/material/chips';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from '@angular/material/core';
@Component({
imports: [
MatButtonModule,
MatCardModule,
// Only import what you need
],
})
```
## Common Component Patterns
### Buttons
```html
Basic
Raised
Flat
Stroked
settings
add
delete
Submit
```
### Form Fields
```html
Email
email
Enter your email address
@if (emailControl.hasError('email')) {
Invalid email format
}
Priority
@for (option of priorities; track option.value) {
{{ option.label }}
}
Description
{{ descriptionControl.value?.length || 0 }}/500
```
### Cards
```html
{{ task().title }}
Due: {{ task().dueDate | date }}
{{ task().description }}
Edit
Delete
```
### Dialog
```typescript
// dialog.ts
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
export interface DialogData {
title: string;
message: string;
}
@Component({
selector: 'app-confirm-dialog',
imports: [MatDialogModule, MatButtonModule],
template: `
{{ data.title }}
{{ data.message }}
Cancel
Confirm
`,
})
export class ConfirmDialog {
readonly data = inject(MAT_DIALOG_DATA);
}
// Usage in parent component
readonly dialog = inject(MatDialog);
openConfirmDialog(): void {
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
width: '400px',
data: { title: 'Confirm Delete', message: 'Are you sure?' },
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.performDelete();
}
});
}
```
### Table with Pagination and Sorting
```typescript
import { MatTableDataSource } from "@angular/material/table";
import { MatPaginator } from "@angular/material/paginator";
import { MatSort } from "@angular/material/sort";
@Component({
imports: [MatTableModule, MatPaginatorModule, MatSortModule],
template: `
Name
{{ row.name }}
Status
{{ row.status }}
`,
})
export class DataTable implements AfterViewInit {
displayedColumns = ["name", "status"];
dataSource = new MatTableDataSource- ();
readonly paginator = viewChild(MatPaginator);
readonly sort = viewChild(MatSort);
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator() ?? null;
this.dataSource.sort = this.sort() ?? null;
}
}
```
### Snackbar
```typescript
readonly snackBar = inject(MatSnackBar);
showSuccess(message: string): void {
this.snackBar.open(message, 'Close', {
duration: 3000,
horizontalPosition: 'end',
verticalPosition: 'top',
panelClass: ['success-snackbar'],
});
}
showError(message: string): void {
this.snackBar.open(message, 'Dismiss', {
duration: 5000,
panelClass: ['error-snackbar'],
});
}
```
## Theming
### Theme Configuration (styles.scss)
```scss
@use "@angular/material" as mat;
// Define palettes
$primary: mat.m2-define-palette(mat.$m2-indigo-palette);
$accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400);
$warn: mat.m2-define-palette(mat.$m2-red-palette);
// Create theme
$theme: mat.m2-define-light-theme(
(
color: (
primary: $primary,
accent: $accent,
warn: $warn,
),
typography: mat.m2-define-typography-config(),
density: 0,
)
);
// Apply theme
@include mat.all-component-themes($theme);
// Dark theme
$dark-theme: mat.m2-define-dark-theme(
(
color: (
primary: $primary,
accent: $accent,
warn: $warn,
),
)
);
.dark-theme {
@include mat.all-component-colors($dark-theme);
}
```
### Component-Level Styling
```scss
// component.scss
@use "@angular/material" as mat;
:host {
display: block;
}
.custom-card {
@include mat.elevation(4);
&:hover {
@include mat.elevation(8);
}
}
```
## CDK Utilities
```typescript
// Drag and Drop
import { CdkDragDrop, DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop';
@Component({
imports: [DragDropModule],
template: `
@for (item of items(); track item.id) {
{{ item.name }}
}
`,
})
export class DragList {
drop(event: CdkDragDrop): void {
moveItemInArray(this.items(), event.previousIndex, event.currentIndex);
}
}
// Virtual Scrolling
import { ScrollingModule } from '@angular/cdk/scrolling';
@Component({
imports: [ScrollingModule],
template: `
{{ item.name }}
`,
})
```
## Checklist
- [ ] Import only required Material modules
- [ ] Use `appearance="outline"` for form fields
- [ ] Provide proper `mat-label` for form fields
- [ ] Use `mat-error` for validation messages
- [ ] Include `aria-label` for icon buttons
- [ ] Use theme colors (`primary`, `accent`, `warn`)
- [ ] Apply proper elevation for cards and dialogs