While Angular 18 projects use standalone components by default, the ecosystem still includes NgModule-based libraries — most importantly Angular Material, which provides a comprehensive component library. Knowing how to import and configure NgModule-based libraries in a standalone application, and how to configure global providers (animations, theming) in app.config.ts, is essential for building polished Angular applications. Angular Material is the most commonly used component library in the Angular ecosystem and integrates directly with the BlogApp’s form and UI components.
Angular Material with Standalone Components
// npm install @angular/material @angular/cdk
// ── app.config.ts — Material global providers ─────────────────────────────
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(),
provideAnimationsAsync(), // required for Material animations
],
};
// ── styles.scss — Material theme ──────────────────────────────────────────
// @use '@angular/material' as mat;
//
// html, body { height: 100%; }
// body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
//
// $blogapp-theme: mat.define-theme((
// color: (
// theme-type: light,
// primary: mat.$azure-palette,
// tertiary: mat.$blue-palette,
// ),
// ));
//
// html { @include mat.all-component-themes($blogapp-theme); }
// ── Using Material components in standalone components ────────────────────
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';
@Component({
selector: 'app-post-form',
standalone: true,
imports: [
ReactiveFormsModule,
MatButtonModule, // <button mat-raised-button>, <button mat-stroked-button>
MatInputModule, // <mat-form-field>, <input matInput>
MatCardModule, // <mat-card>, <mat-card-header>, <mat-card-content>
MatIconModule, // <mat-icon>
MatProgressSpinnerModule,
],
template: `
<mat-card>
<mat-card-header>
<mat-card-title>Create New Post</mat-card-title>
</mat-card-header>
<mat-card-content>
<form [formGroup]="form" (submit)="onSubmit()">
<mat-form-field appearance="outline" class="full-width">
<mat-label>Title</mat-label>
<input matInput formControlName="title" placeholder="Post title">
<mat-error *ngIf="form.controls.title.hasError('required')">
Title is required
</mat-error>
</mat-form-field>
<button mat-raised-button color="primary" type="submit"
[disabled]="form.invalid || isSaving()">
@if (isSaving()) {
<mat-spinner diameter="20" />
} @else {
<mat-icon>save</mat-icon> Save Post
}
</button>
</form>
</mat-card-content>
</mat-card>
`,
})
export class PostFormComponent {
private snackBar = inject(MatSnackBar);
isSaving = signal(false);
form = inject(FormBuilder).group({ title: ['', Validators.required] });
onSubmit(): void {
this.snackBar.open('Post saved!', 'Close', { duration: 3000 });
}
}
MatButtonModule) and standalone component imports (like MatButton). Both work in standalone Angular 18 components. The standalone component API (import { MatButton } from '@angular/material/button') is more tree-shakeable — only the specific component is included in the bundle. The module API (MatButtonModule) includes all button-related components. For optimal bundle size in Angular 18, prefer the standalone component imports where available.provideAnimationsAsync() in app.config.ts for lazy-loaded animations — Material components that use animations (tooltips, bottom sheets, snackbars) load animation code asynchronously, reducing the initial bundle size. Use provideAnimations() (synchronous) only if you experience animation timing issues with provideAnimationsAsync(). Most Angular Material animations work correctly with the async variant.styles.scss — without it, all Material components render with no styling (plain, unstyled HTML). The theme configuration uses Angular Material’s Sass theming system. Always add the theme setup as the first step after installing @angular/material. Run ng add @angular/material to have the Angular CLI configure both the theme and the animation provider automatically.Common Mistakes
Mistake 1 — Forgetting provideAnimationsAsync() (Material animations silently disabled)
❌ Wrong — Material tooltips, snackbars, and dialogs open without animation; console warning about missing providers.
✅ Correct — add provideAnimationsAsync() to app.config.ts providers array.
Mistake 2 — Not configuring a Material theme (unstyled components)
❌ Wrong — @angular/material installed but no theme in styles.scss; buttons look like plain HTML buttons.
✅ Correct — run ng add @angular/material to have the CLI configure the theme automatically.