Angular 16+ Signals vs Decorators: Understanding input(), output(), and signal()
Angular 16+ Signals vs Decorators Angular 16 introduced a new Composition API built around signals—a reactive primitive designed to make reactivity in Angular more powerful, predictable, and ergonomic. Along with this, Angular provided new functions: signal(), input(), and output() that offer a modern alternative to the classic @Input() and @Output() decorators. In this article, we’ll explore: What are signal(), input(), and output()? How do they compare with @Input() and @Output()? When should you use which? 1. The New Composition API import { signal, input, output } from '@angular/core'; These are functions, not decorators. They allow defining state and bindings in a more reactive and composable way. Example: @Component({ selector: 'user-card', standalone: true, template: `{{ name() }}` }) export class UserCardComponent { name = input.required(); onClick = output(); } Benefits: Strongly typed with required/optional inputs Fully signal-compatible Perfect for standalone and modern components 2. The Classic Decorator API import { Input, Output, EventEmitter } from '@angular/core'; These are decorators used since Angular 2 for parent-child communication. Example: @Component({ selector: 'user-card', standalone: true, template: `{{ name }}` }) export class UserCardComponent { @Input() name!: string; @Output() onClick = new EventEmitter(); } Benefits: Works with all Angular versions Compatible with modules and older codebases Side-by-Side Comparison Feature @Input() / @Output() input() / output() API Type Decorator Function Introduced In Angular 2 Angular 16 Reactive? No Yes (signals) Required Inputs Manual ! or guards input.required() Works with Signals Manual wrapping needed Native Event System EventEmitter Reactive callback via signals Recommended for Legacy apps, decorator style Modern apps with signals When to Use Each? Use Case Recommended API You’re using signals input() / output() You’re building modern apps input() / output() You’re working with legacy code @Input() / @Output() Using EventEmitter patterns @Output() Summary Angular’s evolution to signals is a major step forward in ergonomics and reactivity. If you’re starting a new Angular project or refactoring components to use the new standalone style, we highly recommend adopting input(), output(), and signal(). However, decorators like @Input() and @Output() remain powerful and necessary when working with older or module-based codebases. Both APIs can coexist, giving you the flexibility to migrate progressively.

Angular 16+ Signals vs Decorators
Angular 16 introduced a new Composition API built around signals—a reactive primitive designed to make reactivity in Angular more powerful, predictable, and ergonomic. Along with this, Angular provided new functions: signal()
, input()
, and output()
that offer a modern alternative to the classic @Input()
and @Output()
decorators.
In this article, we’ll explore:
- What are
signal()
,input()
, andoutput()
? - How do they compare with
@Input()
and@Output()
? - When should you use which?
1. The New Composition API
import { signal, input, output } from '@angular/core';
These are functions, not decorators. They allow defining state and bindings in a more reactive and composable way.
Example:
@Component({
selector: 'user-card',
standalone: true,
template: `{{ name() }}`
})
export class UserCardComponent {
name = input.required<string>();
onClick = output<MouseEvent>();
}
Benefits:
- Strongly typed with required/optional inputs
- Fully signal-compatible
- Perfect for standalone and modern components
2. The Classic Decorator API
import { Input, Output, EventEmitter } from '@angular/core';
These are decorators used since Angular 2 for parent-child communication.
Example:
@Component({
selector: 'user-card',
standalone: true,
template: `{{ name }}`
})
export class UserCardComponent {
@Input() name!: string;
@Output() onClick = new EventEmitter<MouseEvent>();
}
Benefits:
- Works with all Angular versions
- Compatible with modules and older codebases
Side-by-Side Comparison
Feature |
@Input() / @Output()
|
input() / output()
|
---|---|---|
API Type | Decorator | Function |
Introduced In | Angular 2 | Angular 16 |
Reactive? | No | Yes (signals) |
Required Inputs | Manual ! or guards |
input.required |
Works with Signals | Manual wrapping needed | Native |
Event System | EventEmitter | Reactive callback via signals |
Recommended for | Legacy apps, decorator style | Modern apps with signals |
When to Use Each?
Use Case | Recommended API |
---|---|
You’re using signals |
input() / output()
|
You’re building modern apps |
input() / output()
|
You’re working with legacy code |
@Input() / @Output()
|
Using EventEmitter patterns |
@Output() |
Summary
Angular’s evolution to signals is a major step forward in ergonomics and reactivity. If you’re starting a new Angular project or refactoring components to use the new standalone
style, we highly recommend adopting input()
, output()
, and signal()
.
However, decorators like @Input()
and @Output()
remain powerful and necessary when working with older or module-based codebases.
Both APIs can coexist, giving you the flexibility to migrate progressively.