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?

Use this as one explanation rep, then continue with the Angular interview questions cluster or a guided prep path.