docs/en/Community-Articles/2025-11-17-Angular-21-Signals/post.md
Angular 21 introduces one of the most exciting developments in the modern edition of Angular: Signal-Based Forms. Built directly on the reactive foundation of Angular signals, this new experimental API provides a cleaner, more intuitive, strongly typed, and ergonomic approach for managing form state—without the heavy boilerplate of Reactive Forms.
⚠️ Important: Signal Forms are experimental. Their API can change. Avoid using them in critical production scenarios unless you understand the risks.
Traditionally in Angular, building forms has involved several concerns:
Reactive Forms solved many challenges but introduced their own:
Signal Forms solve these problems through:
1." Automatic synchronization
2." Full type safety
3." Schema-based validation
4." Fine-grained reactivity
5." Drastically reduced boilerplate
6." Natural integration with Angular Signals
A form model is simply a writable signal holding the structure of your form data.
import { Component, signal } from '@angular/core';
import { form, Field } from '@angular/forms/signals';
@Component({
selector: 'app-login',
imports: [Field],
template: `
<input type="email" [field]="loginForm.email" />
<input type="password" [field]="loginForm.password" />
`,
})
export class LoginComponent {
loginModel = signal({
email: '',
password: '',
});
loginForm = form(this.loginModel);
}
Calling form(model) creates a Field Tree that maps directly to your model.
Although TypeScript can infer types from object literals, defining explicit interfaces provides maximum safety and better IDE support.
interface LoginData {
email: string;
password: string;
}
loginModel = signal<LoginData>({
email: '',
password: '',
});
loginForm = form(loginModel);
Now:
loginForm.email → FieldTree<string>loginForm.username results in compile-time errorsThis level of type safety surpasses Reactive Forms.
onSubmit() {
const data = this.loginModel();
console.log(data.email, data.password);
}
<p>Current email: {{ loginForm.email().value() }}</p>
Each field exposes:
value()valid()errors()dirty()touched()All as signals.
Signal Forms allow three update methods.
this.userModel.set({
name: 'Alice',
email: '[email protected]',
});
this.userModel.update(prev => ({
...prev,
email: newEmail,
}));
this.userForm.email().value.set('');
This eliminates the need for:
patchValue()setValue()formGroup.get('field')[field]The [field] directive enables perfect two-way data binding:
<input [field]="userForm.name" />
No subscriptions.
No event handlers.
No boilerplate.
Reactive Forms could never achieve this cleanly.
Models can contain nested object structures:
userModel = signal({
name: '',
address: {
street: '',
city: '',
},
});
Access fields easily:
<input [field]="userForm.address.street" />
Arrays are also supported:
orderModel = signal({
items: [
{ product: '', quantity: 1, price: 0 }
]
});
Field state persists even when array items move, thanks to identity tracking.
Validation is clean and centralized:
import { required, email } from '@angular/forms/signals';
const model = signal({ email: '' });
const formRef = form(model, {
email: [required(), email()],
});
Field validation state is reactive:
formRef.email().valid()
formRef.email().errors()
formRef.email().touched()
Validation no longer scatters across components.
Signal-first architecture is the new standard.
Every field is exactly typed.
Signal Forms drastically simplify code.
Signals integrate perfectly.
| Feature | Reactive Forms | Signal Forms |
|---|---|---|
| Boilerplate | High | Very low |
| Type-safety | Weak | Strong |
| Two-way binding | Manual | Automatic |
| Validation | Scattered | Centralized schema |
| Nested forms | Verbose | Natural |
| Subscriptions | Required | None |
| Change detection | Zone-heavy | Fine-grained |
Signal Forms feel like the "modern Angular mode," while Reactive Forms increasingly feel legacy.
@Component({
selector: 'app-login',
imports: [Field],
template: `
<form (ngSubmit)="submit()">
<input type="email" [field]="form.email" />
<input type="password" [field]="form.password" />
<button>Login</button>
</form>
`,
})
export class LoginComponent {
model = signal({ email: '', password: '' });
form = form(this.model);
submit() {
console.log(this.model());
}
}
Minimal. Reactive. Completely type-safe.
Signal Forms in Angular 21 represent a big step forward:
Although these are experimental, they clearly show the future of Angular's form ecosystem. Once you get into using Signal Forms, you may never want to use Reactive Forms again.