Ch. 4 · Angular

Angular Signal Forms Overview

Model forms as signals, bind fields in the template, and reason about validation and derived state in a signal-driven form.

~2 min readadvancedupdated Oct 5, 2026

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);
TypeScript

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.

More in Angular

read ✓Angular · hard

Angular Resource API for Async Data

Load data reactively with the resource API, track loading and error state as signals, and cancel stale requests automatically.

~2 min readread →
read ✓Angular · hard

Angular Zoneless Change Detection

Run Angular without zone.js, drive updates with signals, and understand which async sources still schedule change detection.

~2 min readread →
esc