Angular Signal Forms
RIP CVA, return of the tombstone … or not ?
Coming back from Angular Connect 2025 in London, and I must say the conference was great ! We had a some good content, and it was to occasion to catch up with some friends and people you merely see now and then in the Angular community.
Many talks were about AI, obviously, and how the team is preparing for the next 2 challenges around it:
- How to make tools based on AI better for the whole DX.
- How to make APIs in Angular that will allow to develop AI enabled applications.
About that, you can go read and participate in this RFC :
Signal Forms
Now, of course, one of the main topics was Angular Signal Forms. I will not get into the specifics of this feature that is still in its experimental phase. At the time of writing this article, we should be around Angular 21.0.0-next-4 and it is of course too early to shoot conclusions.
Besides, some very competent folks wrote articles and made videos about it:
But, as I keep giving Angular trainings, I can safely say that one of the worst API of Angular, and therefore one of the least favorite, is the famous Control Value Accessor.
This API allows the developpers to create nice and versatile custom form elements of any nature and interface. This is mandatory in a framework that has opinionated Forms module, unlike VueJs for example.
As I was attending the conference, we had a talk with a demo of the Signal Forms. Pretty standard presentation, but what I was waiting for was the technique to create a custom form control.
Get Alain Boudard’s stories in your inbox
Join Medium for free to get updates from this writer.
The moment came and it was something, I posted a message on X:
But unfortunaltely, I completely forgot how this was done ! I mean I had no idea how to do that as soon as I headed back to my train to Paris ! I was left with a Stackblitz of mine in Angular 21.0.0-next.2 and no custom form control at all.
So, it was time for some investigations. The Signal Forms package is here:
I know how Angular internals are tested, this way I headed to the tests folder and found one very (very) cool implementation:
it('synchronizes with a custom value control', () => {
@Component({
selector: 'my-input',
template: '<input #i [value]="value()" (input)="value.set(i.value)" />',
})
class CustomInput implements FormValueControl<string> {
value = model('');
}
@Component({
imports: [Control, CustomInput],
template: `<my-input [control]="f" />`,
})
class TestCmp {
f = form<string>(signal('test'));
}
const fix = act(() => TestBed.createComponent(TestCmp));
const input = fix.nativeElement.firstChild.firstChild as HTMLInputElement;
const cmp = fix.componentInstance as TestCmp;
// Initial state
expect(input.value).toBe('test');
// Model -> View
act(() => cmp.f().value.set('testing'));
expect(input.value).toBe('testing');
// View -> Model
act(() => {
input.value = 'typing';
input.dispatchEvent(new Event('input'));
});
expect(cmp.f().value()).toBe('typing');
});Did you see that ???
Alright this was enough, I headed to the mentioned interface FormValueControl<T> in the repo. The description is pretty simple:
export interface FormValueControl<TValue> extends FormUiControl {
/**
* The value is the only required property in this contract. A component that wants to integrate
* with the `Control` directive via this contract, *must* provide a `model()` that will be kept in
* sync with the value of the bound `Field`.
*/
readonly value: ModelSignal<TValue>;Now, let’s see how it works in my StackBlitz:
So the actual code of the component is this:
export class Custom implements FormValueControl<string> {
value = model<string>('');
}I couldn’t help but take a look at the [control] directive:
It does mention the infamous ControlValueAccessor in the imports ! What kind of sorcery is that ? Am I looking at a shell or a wrapper around the CVA ? But then here is the revelation, what is the directive:
* Binds a form `Field` to a UI control that edits it. A UI control can be one of several things:
* 1. A native HTML input or textarea
* 2. A signal forms custom control that implements `FormValueControl` or `FormCheckboxControl`
* 3. A component that provides a ControlValueAccessor. This should only be used to backwards
* compatibility with reactive forms. Prefer options (1) and (2).So, the CVA is here for the sake of retrocompatibility, and that’s one of the strengths of Angular indeed.
Yeah, awesome, I have my answer, I wasn’t even aware of this when I sent my message on X, mainly because I don’t follow closely the different works in progress on the main repo. But yeah, this is so much more simple than the CVA ! I love the direction Angular is taking.
Last words: I’m very happy I could meet many great people from the Angular community, Matthieu Riegler, Shai Reznik, Manfred Steyer, Gerome Grignon, and a few people new to me like Mike Ryan or Andres Gesteira and some others I don’t remember the name. Michael Hladky made a really nice conference, even if it was just one day, I really had a great time. And also, running in Hyde Park with the squirels in the morning is always such a great moment !










