The Problem

Angular Material dialogs use the CDK Overlay system. When a dialog does not close properly, the overlay backdrop remains on screen, blocking all user interaction.

Symptoms

  • dialog.close() called but dialog remains visible
  • Backdrop overlay blocks all clicks
  • Multiple dialogs stack on top of each other
  • Browser back button does not close dialog

Real Error Scenario

```typescript // WRONG: Closing before async operation completes constructor(private dialog: MatDialog) {}

async saveAndClose() { await this.saveData(); this.dialogRef.close(); // May fail if called outside NgZone }

// Or: calling close on wrong reference this.dialog.closeAll(); // Closes ALL dialogs, not just this one ```

How to Fix It

Fix 1: Proper Dialog Close Pattern

```typescript @Component({...}) export class EditUserDialog { constructor( public dialogRef: MatDialogRef<EditUserDialog>, @Inject(MAT_DIALOG_DATA) public data: UserData ) {}

onSave() { this.dialogRef.close({ success: true, data: this.form.value }); }

onCancel() { this.dialogRef.close(); } }

// Opening component const dialogRef = this.dialog.open(EditUserDialog, { data: userData });

dialogRef.afterClosed().subscribe(result => { if (result?.success) { this.handleSave(result.data); } }); ```

Fix 2: Handle Dialog Close in NgZone

```typescript constructor( private dialogRef: MatDialogRef<EditUserDialog>, private ngZone: NgZone ) {}

onSave() { this.saveService.update(this.form.value).subscribe({ next: () => { this.ngZone.run(() => { this.dialogRef.close({ success: true }); }); }, error: (err) => { this.error = err.message; } }); } ```

Fix 3: Close All Dialogs on Navigation

typescript
// In app.component.ts
constructor(private dialog: MatDialog, private router: Router) {
  this.router.events.subscribe(event => {
    if (event instanceof NavigationStart) {
      this.dialog.closeAll();
    }
  });
}

Fix 4: Handle Escape Key and Backdrop Click

```typescript const dialogRef = this.dialog.open(EditUserDialog, { data: userData, disableClose: false, // Allow closing with Escape and backdrop click hasBackdrop: true, backdropClass: 'custom-backdrop' });

// Prevent closing during save this.isSaving = true; dialogRef.disableClose = true;

this.saveService.update(data).subscribe({ next: () => { dialogRef.disableClose = false; dialogRef.close(); } }); ```

Fix 5: Force Close Overlay

typescript
// Last resort: directly access overlay
this.dialogRef.componentInstance.dialogRef.close();
// Or via OverlayRef
this.dialog.getDialogs().forEach(ref => ref.close());