Forms
Kikita UI is Signal Forms first: put the control directive and [formField] on the same element and wrap it in kui-field for the label, hint, error and required marker.
Place the Kikita control directive and the Angular Signal Forms formField binding on the same native element, then wrap it with kui-field when the UI needs a visible label, hint, error or required marker.
import { signal } from '@angular/core';
import { email, form, minLength, required } from '@angular/forms/signals';
const model = signal({
email: '',
project: '',
});
const profileForm = form(model, (path) => {
required(path.email, { message: 'Email is required' });
email(path.email, { message: 'Enter a valid email' });
required(path.project, { message: 'Project is required' });
minLength(path.project, 3, { message: 'Use at least 3 characters' });
});- A native control with
[formField]projected insidekui-fieldlets the field infer the required marker from the Signal Formsrequired(...)metadata and render the first error message when one is available. - Use an explicit
requiredonkui-fieldonly when the marker should be forced without a validator. UsehideErrorswhen the field should keep the invalid styling without rendering automatic error text. - Custom Kikita form controls should prefer the Angular Signal Forms contracts
FormValueControlandFormCheckboxControl, not a ControlValueAccessor, unless a compatibility layer is explicitly needed.
kui-field owns the label, hint, error, required marker and aria-describedby wiring, so do not write them by hand for normal field usage.
<kui-field label="Label" hint="Optional helper text">
<input kuiInput [formField]="form.field" />
</kui-field> For Signal Forms controls put range constraints in the form schema with min(...) and max(...). Do not add native min or max attributes to an element that has [formField]; Angular binds those native properties from the schema metadata.
Use projected marker directives only when the field needs custom template logic.
<kui-field>
<label kuiLabel>Email</label>
<input kuiInput type="email" [formField]="profileForm.email" />
<p kuiHint>Use your work email</p>
@if (showEmailError()) {
<p kuiError>Email is required</p>
}
</kui-field> Do not use [hidden] for custom errors. Prefer Angular control flow (@if) so hidden error content is not rendered or referenced by assistive technology.
kui-segmented and kui-otp-input implement the Signal Forms control contract themselves, so formField goes on the component.
<kui-field label="View">
<kui-segmented [formField]="myForm.view">
<button kuiSegment value="list">List</button>
<button kuiSegment value="grid">Grid</button>
</kui-segmented>
</kui-field>
<kui-field label="Verification code">
<kui-otp-input [formField]="signInForm.code" />
</kui-field>- Both implement
FormValueControl<string>, so[formField]bindsdisabled,readonly,invalid,errorsandtouched.kui-otp-inputalso bindsrequired;kui-segmentedhas no required state because it always shows one active segment. - Both implement
focus(options?), sofield().focusBoundControl()reaches the first focusable part (the selected segment or the first OTP cell) instead of the non-focusable group host.
How the field and its controls expose validation to assistive technology.
kui-fieldexposes its required state, from the explicitrequiredinput or a Signal Formsrequired(...)validator, asaria-requiredon Input, Textarea, Checkbox, Switch, Number Input, Color Input and the other controls that support it. Snapshot tests of the rendered markup change accordingly.- Signal Forms writes the raw, untouched-gated validity into the
invalidof a native control. The controls therefore gatearia-invalidand the invalid styling by the touched state when[formField]is present, so a required but empty control does not turn red before the user has interacted with it. This matches the automatic error text ofkui-field. - Outside Signal Forms the
invalidinput is a plain manual flag, for example for a server verdict on a one-time code. - A control inside
kui-fieldtakes its id,aria-describedbyand invalid state from the field, so the label targets the control and the hint and error are announced.