dotnet / dotnet/aspnetcore

Signals (Reactivity Components) for Blazor Interactive Render Modes

Open
#67,329 10 comments 6 reactions 0 assignees View on GitHub
api-proposal api-suggestion area-blazor design-proposal
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

## Summary

This proposal introduces a native-like reactive state management paradigm to Blazor using Signals (as in Angular Signals: https://angular.dev/guide/signals). It provides automatic dependency tracking to update components when data changes, eliminating the need to manually invoke `StateHasChanged()`.

## Motivation and goals

* Blazor does not automatically trigger UI updates for state changes
occurring outside of standard UI event handlers or input parameter updates (e.g., inside background threads, async tasks, or timer callbacks). Developers are forced to manually invoke StateHasChanged(), which leads to boilerplate, error-prone code, and
maintenance overhead.
* Provide a declarative mechanism inspired by modern frameworks (like
Angular Signals) that automatically intercepts reads and triggers precise, automated
component updates.

## In scope

1. Reactive primitives for "state management" (`Signal`, `Computed` and friends)
2. Track dependencies between those so we know when to re-render something and update the dependency graph

## Out of scope

1. I am not sure how SSR fits in here at this point in time. This proposal is strictly meant for Interactive Server/WASM.
2. Angular has many many more "signal" like things (`resource` or `httpResource` or even complete forms). While "nice", the initial batch of 3 to 5 (like `Effect` or `Input`) would be "good enough".

## Risks / unknowns

Without deeply integrating into the Blazor Rendering Pipeline itself, we would need a wrapper component handling subscriptions etc. Therefore this could lead to a major driver of complexity inside the Blazor Renderer itself.

## Examples

Here is an example taken from my [blogpost](https://steven-giesel.com/blogPost/495d87ca-61df-4c52-a253-8ba4abc186b7/signals-in-blazor) where I dabbled with the idea. It utilizes a reactive wrapper as boundary. Ideally we wouldn't have that in the final design.

```razor
@page "/Signal"
@implements IDisposable

Signal use

Elapsed time: @elapsedMilliseconds.Value milliseconds


Computed elapsed time: @elapsedSeconds.Value seconds

@code {
private readonly Signal elapsedMilliseconds = Signals.Signal(0);
private Computed elapsedSeconds = null!;
private Timer? timer;

protected override void OnInitialized()
{
elapsedSeconds = Signals.Computed(() => elapsedMilliseconds.Value / 1000);
timer = new Timer(
_ => elapsedMilliseconds.Update(value => value + 1000),
null,
TimeSpan.Zero,
TimeSpan.FromSeconds(1));
}

public void Dispose()
{
timer?.Dispose();
}
}
```

Contributor guide

Open the contributing guide

Research direction

No implementation files or tests are named. Start by reviewing the Blazor rendering pipeline and the linked Signals example, then determine the design for Signal, Computed, dependency tracking, and component updates in Interactive Server/WASM modes. Done means the proposal has an agreed implementation shape and clearly defined scope.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
frontend, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.