Interview answer drill

Use this Angular interview question to rehearse a quick answer, common mistake, follow-up, and production pitfall.

What Is ControlValueAccessor in Angular and Why Is It Better Than Custom Two-Way Binding?Frontend interview answer

HighIntermediateAngular
Interview focus

This Angular interview question tests whether you can explain Angular ControlValueAccessor vs custom two-way binding: real forms integration and pitfalls, connect it to production trade-offs, and handle common follow-up questions.

  • Angular ControlValueAccessor vs custom two-way binding: real forms integration and pitfalls explanation without falling back to memorized docs wording
  • Forms and Controlvalueaccessor reasoning, edge cases, and production failure modes
  • How you would answer the most likely Angular interview follow-up
Practice more Angular interview questions
Interview quick answer

ControlValueAccessor is the bridge that makes a custom Angular component behave like a real form control. The useful comparison is not just value syncing, but validation, touched or dirty state, disabled propagation, and the production pitfalls of relying on custom two-way binding instead.

Full interview answer

Forms contract

ControlValueAccessor is not just another way to sync a value. It is the contract that makes a custom Angular component behave like a real form control inside Angular Forms. That is the production difference: validation, touched/dirty state, reset behavior, and disabled handling keep working instead of being rebuilt with fragile custom two-way bindings.

Broken vs correct example

A plain @Input() value plus @Output() valueChange can mirror text, but it does not automatically propagate markAsTouched(), setDisabledState(), or form resets. A proper CVA implements writeValue, registerOnChange, registerOnTouched, and setDisabledState so the Angular form API stays in charge.

Decision rule

  • Use simple input/output binding for isolated value sync outside Angular Forms.
  • Use CVA the moment the component must act like a real form control.
  • If disabled, touched, validation, or reset behavior matters, custom two-way binding stops being enough.

Why not just use custom two-way binding?

Two-way binding like [(value)] only synchronizes a value. It does not integrate with Angular Forms, so you lose validation, touched/dirty states, disabled state, and form-level APIs. CVA plugs your component into the entire forms ecosystem.

Capability

Custom [(value)] binding

ControlValueAccessor

Works with Reactive Forms / ngModel

❌ No

✅ Yes

Supports validators

❌ No

✅ Yes

Tracks touched / dirty / pristine

❌ No

✅ Yes

Supports disabled state

❌ Manual hacks

✅ Built-in via setDisabledState

Integrates with FormGroup / FormControl

❌ No

✅ Yes

Two-way binding vs ControlValueAccessor

Minimal CVA implementation

A CVA has four responsibilities:
writeValue: Angular → component
registerOnChange: component → Angular
registerOnTouched: mark as touched
setDisabledState: handle disabled

TYPESCRIPT
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-rating',
  template: `
    <button *ngFor="let n of [1,2,3,4,5]" (click)="set(n)" [disabled]="disabled">
      {{ n }}
    </button>
  `,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => RatingComponent),
      multi: true
    }
  ]
})
export class RatingComponent implements ControlValueAccessor {
  value = 0;
  disabled = false;

  private onChange = (v: number) => {};
  private onTouched = () => {};

  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);   // notify Angular Forms
    this.onTouched();   // mark as touched
  }
}
                  

Using it like a real form control

HTML
<form [formGroup]="form">
  <app-rating formControlName="rating"></app-rating>
</form>
                  

Why this is strictly better than custom two-way binding

With CVA, your component becomes a first-class Angular form control. It participates in validation, form submission, reset, disabled state propagation, and form-level state tracking. Two-way binding only moves a value around—it does not integrate into the forms system.

Real-world requirement

Without CVA

With CVA

Disable the whole form

❌ You must wire every input manually

✅ setDisabledState is called automatically

Mark control as touched

❌ Manual hacks

✅ Angular handles it

Show validation errors

❌ Not integrated

✅ Works via FormControl

Reset the form

❌ Manual reset logic

✅ Angular resets automatically

Why CVA scales in real apps

Senior-level pitfalls

• Forgetting to call onTouched() (control never becomes touched)
• Not implementing setDisabledState (disabled forms don’t work)
• Mutating internal state without calling onChange
• Using custom two-way binding for components that should be form controls

Interview summary

ControlValueAccessor is Angular’s official way to make a custom component behave like a real form control. It integrates with Reactive Forms and ngModel, supports validation, touched/dirty state, disabled handling, and form APIs. Custom two-way binding only syncs a value and does not integrate with Angular Forms, which makes it unsuitable for serious form components.

Similar questions
Guides
Preparing for interviews?