Angular has two form strategies. Template-driven forms keep logic in the template — great for simple forms. Reactive forms keep logic in the component class — better for complex validation, dynamic fields, and testing.
Template-Driven Forms
Requires FormsModule in your module. Use ngModel to bind inputs:
// app.module.ts
import { FormsModule } from '@angular/forms';
@NgModule({ imports: [FormsModule, ...] })<form #loginForm="ngForm" (ngSubmit="onSubmit(loginForm)">
<div>
<label for="email">Email</label>
<input
id="email"
name="email"
type="email"
[(ngModel)="model.email"
required
email
#emailField="ngModel">
<span *ngIf="emailField.invalid && emailField.touched">
Enter a valid email address.
</span>
</div>
<button type="submit" [disabled="loginForm.invalid">Login</button>
</form>export class LoginComponent {
model = { email: '', password: '' }
onSubmit(form: NgForm) {
if (form.valid) console.log(this.model)
}
}Reactive Forms
Requires ReactiveFormsModule. Define the form structure in the component class:
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
export class RegisterComponent implements OnInit {
form!: FormGroup
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form = this.fb.group({
name: ['', [Validators.required, Validators.minLength(2)]],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
})
}
get name() { return this.form.get('name')! }
get email() { return this.form.get('email')! }
get password() { return this.form.get('password')! }
onSubmit() {
if (this.form.valid) console.log(this.form.value)
}
}<form [formGroup="form" (ngSubmit="onSubmit()">
<input formControlName="name">
<span *ngIf="name.invalid && name.touched">Name is required (min 2 chars).</span>
<input type="email" formControlName="email">
<span *ngIf="email.invalid && email.touched">Valid email required.</span>
<input type="password" formControlName="password">
<span *ngIf="password.invalid && password.touched">Password must be 8+ chars.</span>
<button type="submit" [disabled="form.invalid">Register</button>
</form>Live Form Example
Here's a registration form with real-time validation — the kind Angular would generate:
Ctrl+Enter
HTML
CSS
JS
Preview
Built-in Validators
| Validator | What it checks |
|---|---|
Validators.required | Field is not empty |
Validators.email | Valid email format |
Validators.minLength(n) | At least n characters |
Validators.maxLength(n) | At most n characters |
Validators.pattern(regex) | Matches a regex |
Validators.min(n) | Number ≥ n |
Validators.max(n) | Number ≤ n |
You can also write custom validators — a function that returns null (valid) or an error object.