Skip to content

Commit 18d23cc

Browse files
authored
[CL-875] ADR 0029 - Adopt Angular Signals for Component State (#638)
1 parent f3422e6 commit 18d23cc

File tree

5 files changed

+92
-3
lines changed

5 files changed

+92
-3
lines changed

docs/architecture/adr/0003-observable-data-services.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ Chosen option: **Observable data services**, because
3333
- The work towards a reactive data model will allow us to adopt patterns like NGRX in the future
3434
should it be needed.
3535

36+
:::info Updated Guidance
37+
38+
This ADR remains valid for business logic services, but [ADR 0029][signals] introduces Angular
39+
Signals as the preferred approach over RxJS for view layer code (components, directives, pipes, and
40+
UI-coupled services).
41+
42+
:::
43+
3644
### Example
3745

3846
#### Organizations
@@ -95,3 +103,4 @@ NGRX is the most popular Redux implementation for Angular. For more details, rea
95103
[observable]:
96104
https://blog.angular-university.io/how-to-build-angular2-apps-using-rxjs-observable-data-services-pitfalls-to-avoid/
97105
[redux-motivation]: https://redux.js.org/understanding/thinking-in-redux/motivation
106+
[signals]: ./0029-angular-signals.md

docs/architecture/adr/0026-dotnet-dependency-injection-enhancements.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ as they are expected to always be included in the host -- those services are `IL
107107

108108
## Considered options
109109

110-
- **Ad-hoc usage** - Where we are today, the `TryAdd` overloads are allowed to be used and are used
110+
- **Ad hoc usage** - Where we are today, the `TryAdd` overloads are allowed to be used and are used
111111
occasionally throughout the codebase but they is no outside encouragement to use them.
112112
- **Encourage usage** - Start encouraging usage through team training and encouragement to use them
113113
in code reviews but don't make any automatic check to enforce usage.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
adr: "0029"
3+
status: "Accepted"
4+
date: 2025-11-24
5+
tags: [clients, angular]
6+
---
7+
8+
# 0028 - Adopt Angular Signals for Component State
9+
10+
<AdrTable frontMatter={frontMatter}></AdrTable>
11+
12+
## Context and Problem Statement
13+
14+
Angular has adopted a new reactive primitive, signals. Signals have various improvements over RxJS:
15+
performance, simplicity, and deeper integrations into the rest of the framework.
16+
17+
RxJS will become an optional dependency of Angular. Certain asynchronous workflows will still
18+
benefit from RxJS (signals are synchronous). Furthermore, being a part of the core Angular library,
19+
Angular signals cannot readily be used in non-Angular environments.
20+
21+
As such, Signals should be the default when operating _in the view layer_: components, directives,
22+
pipes, and services that are tightly coupled to the UI/Angular. Services that primarily deal with
23+
business logic should prefer RxJS to maximize portability (or, even better, be moved to the Rust
24+
SDK).
25+
26+
## Decision
27+
28+
Signal-based APIs (inputs, outputs, child queries) will be required in components and directives via
29+
linting:
30+
31+
- `@Input()``input()`
32+
- `@Output()``output()`
33+
- `@ViewChild`/`@ContentChild``viewChild()`/`contentChild()`
34+
35+
Services tightly coupled to Angular should use signals. Services with non-presentational business
36+
logic should prefer RxJS for portability. Use `toSignal()` and `toObservable()` to bridge between
37+
RxJS and signals when necessary.
38+
39+
## Implementation Plan
40+
41+
New code must use signal-based APIs; existing code will be migrated gradually. Angular provides
42+
automatic code migrations for signal
43+
[inputs](https://angular.dev/reference/migrations/signal-inputs) and
44+
[queries](https://angular.dev/reference/migrations/signal-queries).
45+
46+
Much of `libs/components` was updated using these migrators:
47+
https://github.com/bitwarden/clients/pull/15340
48+
49+
See the
50+
[Angular Modernization Guide](https://contributing.bitwarden.com/contributing/code-style/web/angular-migration-guide/#signals)
51+
for more information.
52+
53+
## Consequences
54+
55+
**Positive:**
56+
57+
- Improved performance and simpler change detection
58+
- Clear path to removing Zone.js dependency
59+
- Better debugging experience
60+
- Aligned with Angular's direction
61+
- Simpler than RxJS for many common use cases
62+
63+
**Negative:**
64+
65+
- Temporary complexity during migration with mixed RxJS/Signals patterns
66+
- Learning curve for team members unfamiliar with signals
67+
- Migration effort required for existing codebase
68+
69+
## Reasons against other options
70+
71+
- Disallow usage of signals and only use RxJS for reactivity.
72+
- This is a non-starter. Signals are being built into Angular.
73+
- Continue the status quo of ad hoc usage.
74+
- Having multiple ways to do the same thing leads to analysis paralysis and complicated code.
75+
- Signals + OnPush change detection provide a clear path to removing Zone.js. With that comes
76+
notable performance and debugging improvements.
77+
78+
## Further reading
79+
80+
- [Angular docs](https://angular.dev/guide/signals)

docs/architecture/security/definitions.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ be able to do, and what they want to achieve, possibly even not having anything
1212
achieve, just the notion of "I want a secure product".
1313

1414
A formal approach here is needed: to aid in communication and to also provide a clear set of goals
15-
to achieve. This applies both to ad-hoc conversations in which the participants don't yet share a
15+
to achieve. This applies both to ad hoc conversations in which the participants don't yet share a
1616
common understanding of security goals and the assumed attacker, but it also applies to
1717
long-standing assumed security we want to achieve for our clients, communication protocols, and
1818
cryptography. This is not limited to cryptographic topics.

docs/contributing/code-style/web/angular.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ component "Organization Reports Module" {
212212
@enduml
213213
```
214214
215-
## Reactivity ([ADR-0003](../../../architecture/adr/0003-observable-data-services.md))
215+
## Reactivity ([ADR-0003](../../../architecture/adr/0003-observable-data-services.md) & [ADR-0029](../../../architecture/adr/0029-angular-signals.md))
216216
217217
We make heavy use of reactive programming using [Angular Signals][signals] & [RxJS][rxjs]. Generally
218218
components should always derive their state reactively from services whenever possible.

0 commit comments

Comments
 (0)