Signal forms describe a form as a tree of signals, so field values, validity and derived state are computable values rather than observables or imperatively managed controls. They align forms with Angular’s signal reactivity and make derived state, such as enabling a submit button, a simple computed value.
Before you start
You should be comfortable with signals and reactive forms. This article assumes a recent Angular version that exposes the signal-forms API; older versions use reactive forms.
Step-by-step walkthrough
Step 1: Declare the model as signals
A form is built from a model object whose fields are signals, so reading a field gives the current value and writing it updates the form. Derived values such as disabled, dirty and valid are signals you can compute from the field tree instead of subscribing to status changes.
Step 2: Bind fields in the template
Directives bind an input to a field, so the template reflects the signal and updates it on input. Because the binding is signal-based, change detection updates only the parts that depend on the changed field, which is the performance advantage over a large reactive form.
Step 3: Attach validation to fields
Validation rules are declared on the field and their results are exposed as signals, so an error message renders from field.errors() and a submit button reads the form’s valid() signal. Cross-field rules read other fields as signals, which keeps the dependency explicit.
Worked scenario
The form is a model of signals, and validity is a derived signal.
interface Login {
email: string;
password: string;
}
const model = signal<Login>({ email: '', password: '' });
const email = computed(() => model().email);
const canSubmit = computed(() => email().includes('@') && model().password.length >= 8);Walk through the example
Reading email() yields the current value, and canSubmit recomputes whenever the model changes. A submit button binds to canSubmit, so it enables as soon as both conditions hold, without a separate valueChanges subscription. Validation and derived state are plain computations over signals.
Common mistake
Mixing signal forms with a FormGroup, which creates two sources of truth for the same field. Another is calling model() deep in a template in a way that reads every field, which couples unrelated parts of the form and loses the fine-grained update benefit.
Verify the behavior
Change a field and assert that only dependent computed values recompute by logging them. Assert canSubmit flips with valid and invalid input. Add a cross-field rule, such as password matching, and confirm the error signal updates when either field changes.
Interview exercise
Why are derived values like valid signals rather than subscriptions?
Answer and reasoning
Because validity is a function of the current field values, which are signals, so computed expresses it declaratively and recomputes automatically when inputs change. A subscription requires manual setup and teardown and can go stale or leak. Signals also let change detection update only the consumers of a value, which is what makes the form efficient.
Continue learning
Compare reactivity in Angular signal derived values and signal immutability. Read the Angular signal forms guide and try the Angular interview questions.