Signals are a new reactivity model introduced in Angular 16+ to handle state changes in a simpler and more efficient way.
They offer a reactive way to manage and share data across components without relying heavily on RxJS or manual ChangeDetectionStrategy configuration.
Think of a signal as a reactive variable — when its value changes, any place that uses it is automatically updated.
count().You can create a signal in an Angular component using the signal() function from @angular/core.
// Creating and using a simple signal
import { signal } from '@angular/core';
const counter = signal(0); // initial value is 0
counter(); // read the current value (returns 0)
counter.set(5); // set a new value
counter.update(value => value + 1); // update based on the previous value
In templates, you must always call the signal like a function:
{{ count() }}{{ count }}
// counter.component.ts
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
templateUrl: './counter.component.html'
})
export class CounterComponent {
count = signal(0); // reactive state
increment() {
this.count.update(value => value + 1); // increase the current value
}
reset() {
this.count.set(0); // reset to the initial value
}
}
<!-- counter.component.html -->
<p>Current Count: {{ count() }}</p>
<button (click)="increment()">Increment</button>
<button (click)="reset()">Reset</button>
The count signal holds the current value of the counter. Whenever increment() or reset() is called, the signal’s value changes and Angular automatically re-renders any bindings that use count().
Initial state: Current Count: 0
After clicking "Increment" 3 times: Current Count: 3
After clicking "Reset": Current Count: 0
This happens without you manually triggering change detection — the signal triggers it automatically for all dependents.
signal() for local component state that changes frequently (counters, toggles, small forms).{{ mySignal() }}.signal from @angular/core before using it.update() when the new value depends on the previous one (e.g., counters).isDark = signal(false)) and toggle it with a button in the template.username, isLoggedIn) and display them in the template.update() vs set() and observe how your UI reacts.