Fix Can't bind to 'formGroup' since it isn't a known property of 'form'
TypeScript

Fix Can't bind to 'formGroup' since it isn't a known property of 'form'

The 'Can't bind to formGroup' error occurs when Angular doesn't recognize the formGroup directive. Here's how to fix it in both NgModule and standalone setups.

2026-07-02
8 min read
Fix Can't bind to 'formGroup' since it isn't a known property of 'form'

TL;DR#

If you're seeing Can't bind to 'formGroup' since it isn't a known property of 'form', the cause is almost always a missing ReactiveFormsModule import — either in your NgModule or in the imports array of a standalone component. Fix it by importing ReactiveFormsModule from @angular/forms and adding it to the appropriate imports array.

If that doesn't work, scroll to verify the fix — there are two common variants this guide also covers: child components in lazy-loaded modules and incorrect template syntax.

What you'll see#

plaintext
Can't bind to 'formGroup' since it isn't a known property of 'form'.
If 'formGroup' is a directive, ensure it is included in the @NgModule imports or standalone component imports.

It happens when Angular’s compiler processes your template and encounters <form [formGroup]="myForm">, but ReactiveFormsModule hasn’t been imported into the current module or component scope. The behavior is the same across all Angular versions ≥ v2 — it’s not version-specific, just configuration-specific.

The error appears in three common scenarios:

  • In a lazy-loaded module where ReactiveFormsModule isn’t imported
  • In a standalone component that doesn’t list ReactiveFormsModule in its imports array
  • In a shared module that declares a form component but forgets to re-export ReactiveFormsModule

Root cause#

The formGroup directive is not part of Angular’s core runtime — it’s provided by the @angular/forms package and only becomes available when ReactiveFormsModule is imported. Angular’s Ahead-of-Time (AOT) compiler enforces strict template type checking: if a directive isn’t declared in the current module’s imports array (or the standalone component’s imports), the compiler treats the binding as an unknown property.

This is intentional — it prevents accidental use of directives that may not be available in production builds. The compiler doesn’t know where formGroup comes from, so it flags it as invalid HTML.

The relevant code path is:

ts
// src/app/app.component.ts
import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
 
@Component({
  selector: 'app-root',
  template: `
    <form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
      <input formControlName="email" />
      <button type="submit">Login</button>
    </form>
  `
})
export class AppComponent {
  loginForm = new FormGroup({
    email: new FormControl(''),
    password: new FormControl('')
  });
}

This component fails at compile time because ReactiveFormsModule is not imported — even though the component code itself is correct. Angular sees [formGroup] and says: “I don’t know what formGroup is — it’s not in my directive registry.”

The fix is simple: import ReactiveFormsModule and add it to the imports array. But where? That depends on whether you’re using NgModule or standalone components.

The fix#

Here’s the minimal change that resolves it for both setups.

For NgModule-based apps (pre-v14 or hybrid)#

ts
// src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
 
import { AppComponent } from './app.component';
 
@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    ReactiveFormsModule // ← add this
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

That single change addresses the cause because ReactiveFormsModule registers the formGroup, formControlName, and formGroupName directives with Angular’s DI system — making them available for template compilation.

For standalone components (Angular 14+)#

ts
// src/app/login/login.component.ts
import { Component } from '@angular/core';
import { ReactiveFormsModule, FormGroup, FormControl } from '@angular/forms';
import { FormsModule } from '@angular/forms'; // only if you use ngModel
 
@Component({
  selector: 'app-login',
  standalone: true,
  imports: [
    ReactiveFormsModule // ← required for formGroup
    // optionally: FormsModule
  ],
  template: `
    <form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
      <input formControlName="email" />
      <button type="submit">Login</button>
    </form>
  `
})
export class LoginComponent {
  loginForm = new FormGroup({
    email: new FormControl(''),
    password: new FormControl('')
  });
 
  onSubmit() {
    console.log(this.loginForm.value);
  }
}

Note: If your standalone component is used in a lazy-loaded module, you must import ReactiveFormsModule directly in the component — importing it in the lazy module alone won’t work, because the component’s scope is isolated.

Step by step#

  1. Open app.module.ts (for NgModule) or the standalone component file (e.g., login.component.ts).
  2. Locate the imports array — in @NgModule({ imports: [...] }) or @Component({ imports: [...] }).
  3. Add ReactiveFormsModule to that array.
  4. Save and restart ng serve or run ng build to recompile.

Verify the fix#

Run:

bash
ng build --configuration development

You should see:

plaintext
✔ Browser application bundle has finished.
✔ Compiling with Angular's incremental compiler (incremental mode).
✔ Build completed.

No compiler errors. The form renders, and formGroup binding works — you can type into the inputs and see this.loginForm.value update in the console.

If you’re still seeing the error, two common variants exist:

Variant A — Form used in a lazy-loaded child module#

If LoginComponent lives in LazyModule, and LazyModule imports ReactiveFormsModule, but LoginComponent is standalone and doesn’t import ReactiveFormsModule in its @Component decorator, the error persists.

Fix: Import ReactiveFormsModule directly in the standalone component — lazy modules don’t automatically expose their imports to child standalone components.

Variant B — Using formGroup in a shared component without re-export#

If you declare a form component in a shared module and import ReactiveFormsModule there, but forget to re-export it, consumers of the shared module won’t get the directives.

Fix: Add ReactiveFormsModule to the exports array of your shared module:

ts
// src/app/shared/forms.module.ts
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
 
@NgModule({
  imports: [ReactiveFormsModule],
  exports: [ReactiveFormsModule] // ← critical for shared use
})
export class FormsSharedModule { }

Then import FormsSharedModule instead of ReactiveFormsModule directly in other modules.

Why this happens (and how to avoid it next time)#

Reactive forms are opt-in — Angular deliberately separates FormsModule (for template-driven forms with ngModel) from ReactiveFormsModule (for model-driven forms with FormGroup, FormControl, etc.). This keeps the core bundle lean and avoids accidental mixing of patterns.

To prevent regressions, run ng build in your CI pipeline — if ReactiveFormsModule is missing from the relevant imports array, the build will fail and you’ll catch the issue before merge. You can also write a custom angular-eslint rule that flags components or modules using formGroup or formControlName without ReactiveFormsModule declared in their imports array.

I cover similar Angular type-checking pitfalls — like missing imports, incorrect module scope, and template binding errors — in TypeScript Getter Setter Errors: TS1056, TS1028, TS2378 Fix, where I explain how Angular’s template compiler enforces strict contracts between directives and modules.

Also, if you’re mixing reactive and template-driven forms (e.g., using ngModel alongside formGroup), remember: FormsModule and ReactiveFormsModule can coexist, but both must be imported. Confusing the two is a common source of errors — see JSX.Element vs ReactNode vs ReactElement: TS2322 Fix for a parallel in React’s type system, where missing imports cause similar “unknown property” errors.

Importing ReactiveFormsModule into the correct imports array — whether in an NgModule or a standalone component’s @Component decorator — is the definitive fix for the Can't bind to 'formGroup' error, and once it’s in place your reactive forms will compile and behave as expected.

Frequently Asked Questions

|

Have more questions? Contact us

Written by

Mahdi Br
Mahdi Br

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote

One email a month — no fluff

RLS gotchas, Next.js cache debugging, and the one Supabase setting that bit me last month.