Angular20 min read

Custom Form Controls with ControlValueAccessor

Integrate custom UI widgets (date pickers, rating stars) with Angular forms like built-in inputs.

Grace Thompson
December 21, 2025
0.0k0

ControlValueAccessor (CVA) lets you build a custom input component that works with Angular forms. Example custom controls: - star rating - phone input with country code - date picker wrapper ## Goal: Star rating input that works with formControlName ### Step 1: Create a rating component ```ts import { Component, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { CommonModule } from '@angular/common'; @Component({ selector: 'app-rating', standalone: true, imports: [CommonModule], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => RatingComponent), multi: true, }, ], template: ` <div class="stars"> <button type="button" *ngFor="let s of stars" (click)="set(s)"> {{ s <= value ? '★' : '☆' }} </button> </div> `, }) export class RatingComponent implements ControlValueAccessor { stars = [1, 2, 3, 4, 5]; value = 0; disabled = false; private onChange: (v: number) => void = () => {}; private onTouched: () => void = () => {}; writeValue(v: number): void { this.value = v ?? 0; } registerOnChange(fn: (v: number) => void): void { this.onChange = fn; } registerOnTouched(fn: () => void): void { this.onTouched = fn; } setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } set(v: number) { if (this.disabled) return; this.value = v; this.onChange(v); this.onTouched(); } } ``` ### Step 2: Use it in a reactive form ```html <form [formGroup]="form"> <app-rating formControlName="rating"></app-rating> </form> ``` Now your custom component behaves like a native input. > Next: State management options (Signals store patterns, NgRx, Akita style decisions).

#Angular#Forms#Advanced