Foundations
Signal Forms
Connect values, validation and touched state without maintaining parallel form flags.
Choose simple bindings or a form tree
For a small independent setting, a writable signal with [(value)] or [(checked)] is enough. Use Signal Forms when several fields need shared validation and field state. Angular’s form function creates a field tree from a model signal; FormField connects a Native control to one field.
Signal Forms are part of @angular/forms, not an additional Neural Native initializer. If the application does not already include that package, install the same version as @angular/core. For the tested Angular baseline, the command is:
npm install @angular/forms@22.2.2A complete validated field
Create src/app/email-form.component.ts and place app-email-form inside your root theme. Import FormField in this component’s imports array. Bind [formField] to profileForm.email; do not also bind [(value)] to a second signal on this field.
import { Component, computed, signal } from '@angular/core';
import { FormField, email, form, required } from '@angular/forms/signals';
import { Text, View } from '@ng-native/components';
import { NeuInputComponent } from '@neural-ui/native/input';
import { NeuButtonComponent } from '@neural-ui/native/button';
@Component({
selector: 'app-email-form',
imports: [FormField, Text, View, NeuInputComponent, NeuButtonComponent],
template: `
<view class="content">
<neu-input label="Email address" keyboardType="email-address"
[formField]="profileForm.email" [error]="emailError()" hint="Used for account updates" />
<neu-button label="Save email" (pressed)="save()" />
<text class="feedback">{{ feedback() }}</text>
</view>
`,
styles: `
.content { padding: 24px; gap: 16px; }
.feedback { color: var(--neu-text); }
`,
})
export class EmailFormComponent {
readonly profile = signal({ email: '' });
readonly profileForm = form(this.profile, (path) => {
required(path.email, { message: 'Enter your email address.' });
email(path.email, { message: 'Enter a valid email address.' });
});
readonly feedback = signal('');
readonly emailError = computed(() => {
const field = this.profileForm.email();
return field.touched() ? (field.errors()[0]?.message ?? '') : '';
});
save(): void {
this.profileForm.email().markAsTouched();
if (this.profileForm().invalid()) {
this.feedback.set('Check your email address.');
return;
}
this.feedback.set('Email ready: ' + this.profile().email);
// Persist profile() through your application service.
}
}What is synchronized and what you provide
FormField connects the model value and supported field state, such as invalid, touched, disabled and readonly, through the control contract. Input and Textarea use value; Switch and Checkbox use checked. Neural Native’s error input is the message you choose to display: it does not automatically translate the validator errors.
The example shows the first validator message after the field is touched. Save marks the field as touched before checking the root invalid state, so an untouched empty field gets useful feedback. For server validation, keep separate request state and display the server message without losing the user’s edits.
An email keyboard makes entry easier but does not validate the address. Define required and email rules in the form model, and keep backend validation in your service.