This guide provides detailed migration instructions for upgrading Angular Material across major versions.
Always migrate one major version at a time for the smoothest upgrade experience.
Migrating to v21
Prerequisites
Ensure you’re on the latest v20 release: ng update @angular/core@20 @angular/cli@20
ng update @angular/material@20
Verify your application works correctly before proceeding.
Update Angular and Material
Run the Angular update command: ng update @angular/core@21 @angular/cli@21 @angular/material@21
This command will:
Update package versions
Run automated migrations
Update import statements
Fix deprecated API usage
Update Portal Directives
Replace old portal directive names: TypeScript: // Before
import { TemplatePortalDirective , PortalHostDirective } from '@angular/cdk/portal' ;
// After
import { CdkPortal , CdkPortalOutlet } from '@angular/cdk/portal' ;
Templates: <!-- Before -->
< ng-template portal > Content </ ng-template >
< ng-template portalHost ></ ng-template >
<!-- After -->
< ng-template cdkPortal > Content </ ng-template >
< ng-template cdkPortalOutlet ></ ng-template >
Update SCSS Variables
Update z-index and overlay variables: // Before
@use '@angular/material' as mat ;
.custom-overlay {
z-index : mat . $z-index-overlay ;
}
.backdrop {
background : mat . $dark-backdrop-background ;
}
// After
.custom-overlay {
z-index : mat . $overlay-z-index ;
}
.backdrop {
background : mat . $overlay-backdrop-color ;
}
Remove Animation Imports
Remove imports of animation constants: // Remove these imports
import { matDialogAnimations } from '@angular/material/dialog' ;
import { matMenuAnimations } from '@angular/material/menu' ;
// etc.
// Use CSS/SCSS for animation customization instead
If you were using these for custom animations: .mat-mdc-dialog-container {
animation-duration : 300 ms ;
animation-timing-function : cubic-bezier ( 0.4 , 0.0 , 0.2 , 1 );
}
Remove MatCommonModule
Remove MatCommonModule from imports: // Before
import { MatCommonModule } from '@angular/material/core' ;
@ NgModule ({
imports: [ MatCommonModule , MatButtonModule ]
})
// After - just import specific modules
@ NgModule ({
imports: [ MatButtonModule ]
})
Test your application
Run your test suite and manually test critical paths:
Migrating to v20
Update from v19
ng update @angular/core@20 @angular/cli@20
ng update @angular/material@20
Update TypeScript
Ensure you’re using TypeScript 5.4 or later: // package.json
{
"devDependencies" : {
"typescript" : "~5.4.0"
}
}
Standalone Components
Consider migrating to standalone components: // Before
@ NgModule ({
declarations: [ MyComponent ],
imports: [ MatButtonModule ]
})
export class MyModule {}
// After
@ Component ({
standalone: true ,
imports: [ MatButtonModule ],
// ...
})
export class MyComponent {}
Migrating to v19 (Material Design 3)
Version 19 introduced Material Design 3, which includes visual changes to all components.
Update packages
ng update @angular/core@19 @angular/cli@19
ng update @angular/material@19
Update theme configuration
Replace M2 theme API with M3: @use '@angular/material' as mat ;
// Before (M2)
$theme : mat . m2-define-light-theme ((
color : (
primary: mat . m2-define-palette ( mat . $indigo-palette ),
accent: mat . m2-define-palette ( mat . $pink-palette ),
)
)) ;
// After (M3)
$theme : mat . define-theme ((
color : (
theme - type: light ,
primary: mat . $violet-palette ,
),
)) ;
html {
@include mat . all-component-themes ( $theme );
}
Update density
M3 uses a simpler density API: $theme : mat . define-theme ((
density: (
scale : -1 // More compact
)
)) ;
Test visual changes
All components will look different. Test thoroughly:
Component spacing and sizing
Colors in light and dark modes
Custom overrides
Update packages
ng update @angular/material@19
Keep M2 theme API
Use the M2 compatibility mode: @use '@angular/material' as mat ;
$theme : mat . m2-define-light-theme ((
color : (
primary: mat . m2-define-palette ( mat . $indigo-palette ),
accent: mat . m2-define-palette ( mat . $pink-palette ),
)
)) ;
html {
// Use M2 mixins
@include mat . m2-all-component-themes ( $theme );
}
Enable system tokens (optional)
Use M3 tokens with M2 themes: html {
@include mat . m2-all-component-themes ( $theme );
@include mat . m2-theme ( $theme ); // Generates M3-style tokens
@include mat . system-classes (); // Utility classes
}
Plan M3 migration
M2 compatibility will be maintained but plan to migrate to M3 eventually.
Migrating from AngularJS Material
Migrating from AngularJS Material to Angular Material requires a complete rewrite.
Set up Angular
Create a new Angular application: ng new my-app
cd my-app
ng add @angular/material
Map components
Most AngularJS Material components have Angular equivalents: AngularJS Angular <md-button><button mat-button><md-input-container><mat-form-field><md-select><mat-select><md-dialog>MatDialog service<md-sidenav><mat-sidenav>
Update directive syntax
<!-- AngularJS -->
< md-button ng-click = "ctrl.submit()" >
Submit
</ md-button >
<!-- Angular -->
< button mat-button (click) = "submit()" >
Submit
</ button >
Migrate services
Services work differently in Angular: // AngularJS
angular . module ( 'app' ). controller ( 'MyCtrl' , function ( $mdDialog ) {
$mdDialog . show ({
template: '<div>Hello</div>'
});
});
// Angular
import { MatDialog } from '@angular/material/dialog' ;
@ Component ({ ... })
export class MyComponent {
constructor ( private dialog : MatDialog ) {}
openDialog () {
this . dialog . open ( MyDialogComponent );
}
}
Migrate incrementally
Consider using ngUpgrade to run both frameworks side-by-side during migration.
Common Migration Patterns
Updating Module Imports
import { MatLegacyButtonModule } from '@angular/material/legacy-button' ;
@ NgModule ({
imports: [ MatLegacyButtonModule ]
})
Updating Component Selectors
< mat-form-field appearance = "legacy" >
< input matInput >
</ mat-form-field >
Updating Theme Mixins
@import '~@angular/material/theming' ;
@include mat-core ();
$primary : mat-palette ( $mat-indigo ) ;
Troubleshooting
Build errors after update
Clear cache and reinstall: rm -rf node_modules package-lock.json
npm install
Clear Angular cache:
Check @use syntax: // Correct
@use '@angular/material' as mat ;
// Incorrect
@import '@angular/material/theming' ;
Update test imports: import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed' ;
import { MatButtonHarness } from '@angular/material/button/testing' ;
Use harnesses instead of internals: // Instead of
const button = fixture . nativeElement . querySelector ( '.mat-button' );
// Use
const button = await loader . getHarness ( MatButtonHarness );
Update TypeScript version: npm install -D typescript@latest
Enable strict mode gradually: // tsconfig.json
{
"compilerOptions" : {
"strict" : false , // Enable gradually
"strictNullChecks" : true
}
}
Automated Migrations
Angular CLI provides automated migrations:
# See available migrations
ng update @angular/material --migrate-only
# Run specific migration
ng update @angular/material --migrate-only --from=19 --to=20
Automated migrations handle most common cases but always review changes.
Resources
Breaking Changes Complete list of breaking changes
Angular Update Guide Interactive update guide
GitHub Releases Release notes and changelogs
Community Forum Ask migration questions