skills/dev-skills/angular-developer/references/inputs.md
Inputs allow data to flow from a parent component to a child component. Angular recommends using the signal-based input API for modern applications.
Declare inputs using the input() function. This returns an InputSignal.
import {Component, input, computed} from '@angular/core';
@Component({
selector: 'app-user',
template: `<p>User: {{ name() }} ({{ age() }})</p>`,
})
export class User {
// Optional input with default value
name = input('Guest');
// Required input
age = input.required<number>();
// Inputs are reactive signals
label = computed(() => `Name: ${this.name()}`);
}
<app-user [name]="userName" [age]="25" />
The input function accepts a config object:
import { input, booleanAttribute } from '@angular/core';
@Component({...})
export class CustomButton {
// Alias example
label = input('', { alias: 'btnLabel' });
// Transform example using built-in helper
disabled = input(false, { transform: booleanAttribute });
}
Use model() to create an input that supports two-way data binding.
@Component({
selector: 'custom-counter',
template: `<button (click)="increment()">+</button>`,
})
export class CustomCounter {
value = model(0);
increment() {
this.value.update((v) => v + 1);
}
}
<!-- Two-way binding with a signal -->
<custom-counter [(value)]="mySignal" />
<!-- Two-way binding with a plain property -->
<custom-counter [(value)]="myProperty" />
The legacy API remains supported but is not recommended for new code.
import { Component, Input } from '@angular/core';
@Component({...})
export class Legacy {
@Input({ required: true }) value = 0;
@Input({ transform: trimString }) label = '';
}
input() instead of @Input() for better reactivity and type safety.input.required() for mandatory data to get build-time errors.id, title).