Skip to content

Forms

@xngui/components/form
@xngui/components/form

Signal Forms shell — x-form, x-form-field, validators, and control composition.

Overview

Three layers
  1. 1Schemaform(model, validators)
  2. 2Shellx-form + x-form-field
  3. 3Controlx-input [formField]

Every value control implements Angular's FormValueControl (or checkbox/slider variants) and works standalone with [(value)] — [formField] is optional.

Live preview

Signal Forms schema

form() + validators

Define the model as a signal, then pass a schema callback to form(). Import Angular validators and @xngui extensions from @xngui/components/form.

schema.ts
import { form } from '@angular/forms/signals';import { email, match, required } from '@xngui/components/form';interface ContactModel {  name: string;  email: string;  confirmEmail: string;}const model = signal<ContactModel>({ name: '', email: '', confirmEmail: '' });const contactForm = form(model, (path) => {  required(path.name, { message: 'Name is required' });  required(path.email, { message: 'Email is required' });  email(path.email, { message: 'Enter a valid email' });  match(path.confirmEmail, path.email, { message: 'Emails must match' });});

x-form composition

Template structure

Bind [formField] on the control inside x-form-field — not on the field wrapper. x-form cascades labelMode, look, size, density, and validateOn to descendants.

form.html
<x-form [form]="contactForm" validateOn="touched">  <x-form-field label="Name">    <x-input [formField]="contactForm.name" />  </x-form-field>  <x-form-field label="Email" hint="We never share your email.">    <x-input [formField]="contactForm.email" />  </x-form-field>  <x-form-field label="Confirm email">    <x-input [formField]="contactForm.confirmEmail" />  </x-form-field>  <x-button type="submit" variant="primary">Submit</x-button></x-form>
Cascaded properties
PropertyValuesRole
labelModestatic · float · overLabel layout for nested fields
lookoutline · fill · flat · noneControl chrome
sizexs – xlControl scale tier
densitycompact · comfortable · standardSpacing offsets
validateOndirty · touched · submit · …When errors appear

Label modes

static vs float

labelMode cascades from x-form to x-form-field. Use static for always-visible labels above the control; float animates the label into the field when focused or filled.

Validators

Built-in validators
ValidatorImport fromNotes
required@angular/forms/signalsNon-empty value
email@angular/forms/signalsRFC-style email
minLength / maxLength@angular/forms/signalsString length bounds
min / max@angular/forms/signalsNumeric bounds
pattern@angular/forms/signalsRegExp match
phone@xngui/components/formPhone-like string (7+ digits)
url@xngui/components/formParseable URL
match@xngui/components/formEquals another field
oneOf@xngui/components/formValue in allowed set

Legacy import @xngui/components/validation re-exports the same helpers. See the form demo for a full profile form and the form builder for visual composition.

Validation i18n

Translated validation messages

x-form maps Signal Forms ValidationError objects to translation keys via validationErrorKey, validationErrorParams, and validationErrorFallback from @xngui/components/form-field. Register validation.* keys in provideX translations.

validators.ts
import { provideX } from '@xngui/core/config';import { mergeXTranslations } from '@xngui/core/i18n';export const appConfig = {  providers: [    provideX({      translations: mergeXTranslations({        en: {          'validation.required': 'This field is required',          'validation.email': 'Enter a valid email address',        },      }),    }),  ],};// x-form resolves validationErrorKey(error) → xTranslate pipe// validationErrorParams(error) supplies {{min}}, {{max}}, …

Form controls

Validation timing

validateOn

Set validateOn on x-form (or override per x-form-field) to control when errors appear: dirty, touched, dirty-or-touched, submit, or always. Global default comes from provideX({ config: { validateOn: 'touched' } }).

x-form can show an error summary on submit via errorSummary="submit". Individual fields read validation state from the bound [formField] and reveal errors through x-form-field.