Diagnosing 'mat-form-field must contain a MatFormFieldControl' Errors in Angular Material
A step‑by‑step diagnostic guide for the common Angular Material error 'mat-form-field must contain a MatFormFieldControl', covering module imports, directives, version alignment, and custom control implementation.
03 Jan 2026, 01:33 UTC

Recognizable condition
When you add a new <mat-form-field> (or upgrade Angular/Material), the field may appear unstyled, or the app throws a runtime error such as:
mat-form-field must contain a MatFormFieldControlNullInjectorError: No provider for MatFormField!
The error usually surfaces immediately after the component is instantiated, preventing the form from rendering correctly.
Cause/diagnostic table
| Cause | Typical symptom | Where to look |
|---|---|---|
Missing control‑specific module (e.g., MatInputModule) | Error appears as soon as the field is used; no styling applied | NgModule imports array or standalone component imports |
Control lacks required directive (matInput, matSelect, etc.) | Same error, but the module import is present | Template inside <mat-form-field> |
| Version mismatch between @angular/core and @angular/material | Error after upgrade; sometimes accompanied by missing CSS classes or theming warnings | package.json or output of ng version |
Custom component inside mat-form-field does not implement MatFormFieldControl | Error persists even with correct modules and directives | Custom control class definition |
Ordered checks
- Read the exact console error and note whether it mentions a missing provider or a specific control type.
- Verify that the module matching the control is imported:
MatInputModuleformatInputMatSelectModuleformatSelectMatAutocompleteModuleformatAutocomplete
importsarray of the@Componentdecorator; otherwise, look in the NgModule that declares the component. - Inspect the template inside
<mat-form-field>for the required directive (e.g.,<input matInput>or<mat-select>). If the directive is missing, add it. - Run
ng versionor examinepackage.jsonto confirm that@angular/coreand@angular/materialshare the same major version (e.g., both 16.x). - If you are using a custom control, open its class file and ensure it implements
MatFormFieldControl<T>(providesvalue,stateChanges,placeholder,required,disabled,errorState,controlType,focused,describe(),onContainerClick(), etc.).
Fixes mapped to findings
- Missing module – Add the appropriate import:
// In an NgModule import { MatInputModule } from '@angular/material/input'; @NgModule({ imports: [MatInputModule, /* other imports */], // … }) export class AppModule {} // In a standalone component import { MatInputModule } from '@angular/material/input'; @Component({ selector: 'app-demo', template: `<mat-form-field><input matInput placeholder="Name"></mat-form-field>`, imports: [MatInputModule, MatFormFieldModule] }) export class DemoComponent {} - Missing directive – Ensure the control element carries the directive:
<mat-form-field> <input matInput placeholder="Email"> </mat-form-field> // For a select <mat-form-field> <mat-select> <mat-option *ngFor="let opt of options" [value]="opt.value"><opt.label></mat-option> </mat-select> </mat-form-field> - Version mismatch – Align the versions using the Angular CLI update command:
After changing versions, runng update @angular/core @angular/material # or manually set matching versions in package.json, e.g. # "@angular/core": "^16.2.0", # "@angular/material": "^16.2.0"npm install(oryarn install) and rebuild. - Custom control not implementing MatFormFieldControl – Implement the interface (or extend a built‑in control). A minimal example:
import { MatFormFieldControl } from '@angular/material/form-field'; import { Subject } from 'rxjs'; export class MyCustomControl implements MatFormFieldControl { static nextId = 0; value = ''; placeholder = ''; required = false; disabled = false; errorState = false; controlType = 'my-custom-control'; stateChanges = new Subject(); focused = false; id = `my-custom-control-${MyCustomControl.nextId++}`; describe() { return this.placeholder || `Custom control ${this.id}`; } onContainerClick(event: MouseEvent) { // optionally focus the control } }Remember to provide the control via
providers: [{ provide: MatFormFieldControl, useExisting: forwardRef(() => MyCustomControl) }]in the component.
Escalation criteria
If after performing the checks above the error persists, consider the following escalation steps:
- The problem occurs only in production builds (e.g., after
ng build --prod) – create a minimal reproduction withng new test-appand gradually add your code to isolate the cause. - The error is accompanied by theming or typography regressions after a major Angular Material upgrade (e.g., moving from v14 to v15 where MDC‑based components were introduced). Review the official migration guide for breaking changes.
- You suspect a bug in Angular Material itself – file a minimal, reproducible example on the Angular Material issue tracker with the exact versions of
@angular/coreand@angular/material.
Verification
After applying a fix:
- Run the application (
ng serve) and confirm the form field renders with the expected label floating, input styling, and error-state colors. - Run the unit tests for the component (
ng test) to ensure no new injection errors are introduced. - Manually tab through the form; verify that focus styles appear and that the control updates its
stateChangesobservable (you can log to console in a temporary subscription).
These steps give confidence that the MatFormFieldControl contract is satisfied and that the field works in both development and production builds.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.