When using @oxc-angular/vite to compile an Angular 21 application that uses the Signal Forms API (@angular/forms/signals), the [formField] directive binding appears to be not wired up correctly. The FormField directive is instantiated (its selector [formField] is matched), but its field input never receives the bound value, resulting in the form input silently failing to bind.
No error output is generated to the JS console (that I can see), but the control is simply not bound to the [formField] directive - it wasn't until I looked at the Angular DevTools that I noticed the FormFieldDirective's field signal was in an errored state:
Minimal reproduction
// app.component.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { form, FormField, required } from '@angular/forms/signals';
@Component({
selector: 'app-root',
imports: [FormField],
template: `
<input type="text" [formField]="myForm.firstName" />
<pre>{{ myFormModel().firstName }}</pre>`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
protected readonly myFormModel = signal({
firstName: 'Foo',
email: 'foo@bar.com',
});
protected readonly myForm = form(this.myFormModel, path => {
required(path.firstName);
});
}
Expected behavior
The <input> displays "Foo", and typing updates myFormModel().firstName via two-way signal binding.
Actual behavior
The input is empty. Typing does not update the model. Angular DevTools shows the FormField directive's field input in an error state (NG0950). The FieldState signals (name, value, etc.) are never populated.
If I swap the @oxc-angular/vite plugin with the @analogjs/vite-plugin-angular plugin, everything works as expected.
I did that like this:
// vite.config.ts
import analogAngular from '@analogjs/vite-plugin-angular';
import { angular as oxcAngular } from '@oxc-angular/vite';
import { defineConfig } from 'vite-plus';
const USE_OXC_ANGULAR = true;
export default defineConfig({
plugins: USE_OXC_ANGULAR ? [oxcAngular()] : [analogAngular()],
server: {
host: '0.0.0.0',
port: 4200,
},
});
Bundle size differences
Additionally, when building this small reproduction, the build output when using the OXC Angular plugin vs the AnalogJS Angular plugin is twice the size.
When using @analogjs/vite-plugin-angular (USE_OXC_ANGULAR = false):
$ vp build
VITE+ - The Unified Toolchain for the Web
vite v8.0.5 building client environment for production...
✓ 259 modules transformed.
computing gzip size...
dist/index.html 0.37 kB │ gzip: 0.26 kB
dist/assets/index-D5gCGqZR.js 165.45 kB │ gzip: 51.07 kB
✓ built in 2.03s
When using @oxc-angular/vite (USE_OXC_ANGULAR = true):
$ vp build
VITE+ - The Unified Toolchain for the Web
vite v8.0.5 building client environment for production...
✓ 259 modules transformed.
computing gzip size...
dist/index.html 0.37 kB │ gzip: 0.25 kB
dist/assets/index-DBjttgyu.js 309.79 kB │ gzip: 91.37 kB
✓ built in 195ms
When using
@oxc-angular/viteto compile an Angular 21 application that uses the Signal Forms API (@angular/forms/signals), the[formField]directive binding appears to be not wired up correctly. TheFormFielddirective is instantiated (its selector[formField]is matched), but its field input never receives the bound value, resulting in the form input silently failing to bind.No error output is generated to the JS console (that I can see), but the control is simply not bound to the
[formField]directive - it wasn't until I looked at the Angular DevTools that I noticed theFormFieldDirective'sfieldsignal was in an errored state:Minimal reproduction
Expected behavior
The
<input>displays "Foo", and typing updatesmyFormModel().firstNamevia two-way signal binding.Actual behavior
The input is empty. Typing does not update the model. Angular DevTools shows the
FormFielddirective's field input in an error state (NG0950). TheFieldStatesignals (name,value, etc.) are never populated.If I swap the
@oxc-angular/viteplugin with the@analogjs/vite-plugin-angularplugin, everything works as expected.I did that like this:
Bundle size differences
Additionally, when building this small reproduction, the build output when using the OXC Angular plugin vs the AnalogJS Angular plugin is twice the size.
When using
@analogjs/vite-plugin-angular(USE_OXC_ANGULAR = false):When using
@oxc-angular/vite(USE_OXC_ANGULAR = true):