Compose Forms From Smaller Forms
Nested FormGroups
A FormGroup can contain another FormGroup. This mirrors the shape of nested data so your form value lines up with your API payload.
What you'll learn
- Nest a FormGroup
- Bind with formGroupName
- Read nested values
Real-world forms have structure. A user has a name and an address; an address has a city, postcode, and country. Nested form groups let your form mirror that.
Defining a Nested Group
import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-profile',
standalone: true,
imports: [ReactiveFormsModule],
template: `...`,
})
export class ProfileComponent {
private fb = inject(FormBuilder);
form = this.fb.group({
name: ['', Validators.required],
address: this.fb.group({
city: ['', Validators.required],
zip: '',
country: 'US',
}),
});
} form.value will be { name, address: { city, zip, country } } — exactly the shape your API probably wants.
Binding in the Template
Use formGroupName to enter the nested group, then formControlName for each field inside.
<form [formGroup]="form">
<input formControlName="name" placeholder="Name" />
<fieldset formGroupName="address">
<legend>Address</legend>
<input formControlName="city" placeholder="City" />
<input formControlName="zip" placeholder="Zip" />
<input formControlName="country" placeholder="Country" />
</fieldset>
</form> Accessing Nested Controls
You can dot into typed forms directly.
this.form.controls.address.controls.city.setValue('Berlin');
this.form.controls.address.valueChanges.subscribe(addr => {
console.log('address changed', addr);
}); form.get('address.city') works too but loses the strong typing — prefer the property chain.
Mixing With FormArray
A nested group can sit inside a FormArray, and a FormArray can live inside a group. That is how you build forms like “list of users, each with a list of skills” without any extra plumbing.