Signal Inputs, Outputs & Model

Angular 21 — Replace @Input/@Output decorators with functional signal APIs

About This Feature

Angular 21 provides functional alternatives to decorator-based component I/O. These are now the preferred approach for new components.

  • input(defaultValue) — creates a read-only Signal for incoming data. The value is set by the parent via property binding.
  • input.required<T>() — same as above but the TypeScript compiler enforces that the parent must provide a value.
  • output<T>() — replaces @Output() EventEmitter. Call .emit(value) to fire events.
  • model(defaultValue) — creates a WritableSignal that enables two-way binding ([(property)]). The child can read and write; writes automatically propagate back to the parent's signal.

Code Example

// child component
import { input, output, model } from '@angular/core';

export class SignalCardComponent {
  // Required input signal — compiler enforces parent provides it
  name = input.required<string>();

  // Optional input signal with default value
  color = input('#667eea');

  // model() — two-way bindable; child writes propagate to parent signal
  liked = model(false);

  // output() replaces @Output() EventEmitter
  greet = output<string>();

  onGreet() {
    this.greet.emit(`Hello from ${this.name()}!`);
  }
}

// parent template
<app-signal-card
  [name]="cardName()"
  [color]="cardColor()"
  [(liked)]="isLiked"
  (greet)="onGreet($event)" />

// Reading signals in the child template
{{ name() }}     // read input signal
{{ liked() }}    // read model signal
liked.update(v => !v)  // write model signal → updates parent too

Live Demo

Control the child component from the parent using signals:

(model() in sync — child can also toggle it)

Hello, Angular Developer!

This card uses input(), output(), and model()

model() value: false  (parent & child stay in sync)

Parent signal reads:   cardName() = "Angular Developer"  |  isLiked() = false