Field
Field wraps native controls with label, hint, error, required state, and ARIA wiring.
Import the public field primitive from the package entrypoint.
import {
KuiError,
KuiField,
KuiFieldAffix,
KuiHint,
KuiInput,
KuiInputGroup,
KuiLabel,
provideKuiDefaults,
} from '@kikita-labs/ui';Use kui-field whenever a visible label, hint, error, or required marker is needed.
<div class="basic-field-example">
<kui-field label="Email" hint="Use your work email">
<input kuiInput type="email" placeholder="mira@company.dev" />
</kui-field>
<kui-field label="Project" error="Project name is required" required>
<input kuiInput value="" />
</kui-field>
</div>Bind Angular Signal Forms to the native control with [formField]. The field owns label, hint, error text, the required marker and the ARIA description; Signal Forms owns the form state.
<kui-field label="Project" hint="Minimum 3 characters">
<input kuiInput [formField]="profileForm.project" />
</kui-field>
<!-- hideErrors keeps the invalid state but hides the rendered messages -->
<kui-field label="Project" hint="Minimum 3 characters" hideErrors>
<input kuiInput [formField]="profileForm.project" />
</kui-field>- With a
required(...)validator on the bound field the required marker is inferred; an explicitrequiredinput onkui-fieldoverrides it. - The first error message of the bound field is rendered automatically unless
hideErrorsis set.hideErrorshides every rendered message, including the expliciterrorinput and projectedkuiErrorcontent, but keeps the invalid state.
Use the kuiLabel, kuiHint and kuiError markers when the label, hint or error needs template logic. They keep the same field wiring.
<div class="field-projected-example">
<kui-field label="Email">
<input kuiInput type="email" placeholder="mira@company.dev" />
<p kuiHint>Use your work email</p>
<p kuiError>Email is required</p>
</kui-field>
<kui-field label="API key">
<input kuiInput />
<p kuiHint class="kui-field-message">
<span>Stored encrypted. <a href="#encryption">Learn more</a>.</span>
</p>
</kui-field>
</div>The same markers also exist for the label, which the field wires to the control for you:
<kui-field>
<label kuiLabel>Email</label>
<input kuiInput type="email" [formField]="profileForm.email" />
<p kuiHint>Use your work email</p>
@if (shouldShowEmailError()) {
<p kuiError>Email is required</p>
}
</kui-field>kuiErroris manual content: render it with@ifunder your own visibility rules, and never hide it with[hidden], so it only joins the field semantics when it is shown.- Add
.kui-field-messageto a projected hint or error for icon and text layouts; projected errors stay part ofaria-describedby.
Drop kuiFieldAffix directly inside kui-field for prefix text, suffix text, leading icons or trailing actions. The field switches its control slot to the shared input-group chrome automatically.
<div class="field-affix-example">
<kui-field label="Project URL" hint="The prefix and suffix are visual field chrome.">
<span kuiFieldAffix>https://</span>
<input kuiInput aria-label="Project slug" />
<span kuiFieldAffix>.dev</span>
</kui-field>
<kui-field label="Search">
<kui-icon kuiFieldAffix name="search" />
<input kuiInput aria-label="Search query" />
<button kuiFieldAffix type="button" aria-label="Clear search">
<kui-icon name="x" />
</button>
</kui-field>
</div>- One directive, three looks, detected from the host: any
buttongets compact action styling (do not addkuiButtonorkuiIconButtonto it),kui-icona fixed square icon slot, anything else muted text (theemphasisinput switches it to full color). - A
span kuiLoader kuiFieldAffixis detected as an icon and keeps its ownrole="status"and label.kuiFieldAffixIconandkuiFieldActionremain as explicit overrides for older markup. - Decorative icons use
aria-hidden="true"; interactive field actions must be native buttons with accessible names.
For field chrome the affixes do not cover, build .kui-input-group by hand and import KuiInputGroup. It delegates clicks on non-interactive chrome to the first enabled native control.
<div class="field-input-group-example">
<kui-field label="API key">
<div class="kui-input-group">
<input kuiInput />
<span class="kui-affix-spinner" role="status" aria-label="Checking key"></span>
</div>
</kui-field>
</div>Interactive descendants such as clear buttons, chevrons, visibility toggles, links and the control itself keep their own behavior.
Set defaults.field once for the application or for a subtree. Each option resolves as local input > defaults.field.<option> > built-in default.
import { provideKikitaUi } from '@kikita-labs/ui';
export const appConfig: ApplicationConfig = {
providers: [
provideKikitaUi({
defaults: {
field: {
/* options below */
},
},
}),
],
};| Name | Type | Default | Description |
|---|---|---|---|
| clearable | boolean | — | When true, field controls with clear affordances show a clear button by default. |
| size | 'xs' | 'sm' | 'md' | 'lg' | — | Default kui-field size when no local size input is provided. |
| hideErrors | boolean | — | Hides automatically rendered Angular Signal Forms error messages by default. |
Set any of these on the component or an ancestor to restyle one part. Each token is optional: when it is not set, the part uses the role or scale token in the default column.
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-field-label-gap | CSS custom property | --kui-space-1 | Label gap |
| --kui-field-label-row-gap | CSS custom property | --kui-space-1 | Label row gap |
| --kui-field-affix-font-size | CSS custom property | --kui-text-sm-size | Affix font size |
| --kui-field-spinner-radius | CSS custom property | --kui-radius-full | Spinner corner radius |
Inputs, projected markers, provider defaults and tokens verified against @kikita-labs/ui v2.0.0 public typings.
| Name | Type | Default | Description |
|---|---|---|---|
| label | string | — | Visible label shorthand. Prefer this for simple field labels. |
| hint | string | — | Optional help text rendered below the control and wired through aria-describedby. |
| error | string | — | Explicit error text rendered below the control and wired through aria-describedby. |
| hideErrors | boolean | — | Hides automatic, explicit, and projected error messages while keeping invalid state. |
| required | boolean | — | Explicit required marker override. Omit when Signal Forms can infer it. Also drives aria-required on the projected control. |
| size | 'xs' | 'sm' | 'md' | 'lg' | — | Field spacing and projected control size. Falls back to defaults.field.size, then the global defaults.size. |
| [kuiLabel] / [kuiHint] / [kuiError] | marker directives | - | Projected label, hint and error with the same field wiring. kuiError is manual content: render it with @if. |
| [kuiFieldAffix] | directive | - | Prefix, suffix, icon or action chrome inside the field: button hosts get action styling, kui-icon an icon slot, anything else muted text (emphasis input for full color). kuiFieldAffixIcon and kuiFieldAction are explicit overrides. |
| .kui-input-group / KuiInputGroup | class and directive | - | Hand-built input group chrome; the directive delegates clicks on non-interactive chrome to the first enabled control. |
| KuiFieldOptions | interface | - | Shape of defaults.field: clearable, size and hideErrors. Controls inside the field take an explicit field size first, then their own defaults key, then defaults.field.size. |
Keep field semantics native-first. Let kui-field wire ids and descriptions instead of duplicating ARIA by hand.
- Prefer a visible label through
labelor projectedkuiLabel. - Projected
kuiHintandkuiErrorparticipate inaria-describedby. - The field does not replace the native control role.
- The required marker is visual only (
aria-hidden). The merged required state, from the explicitrequiredinput or a Signal Formsrequired(...)validator, reaches assistive technology asaria-required="true"on the control.kui-fieldnever writes the nativerequiredattribute, so nothing is announced twice. - Controls with a role that supports it receive
aria-required: Input, Textarea, Checkbox, Switch, Number Input, Color Input, Select, Combobox, Date Picker and Time Picker. A single Radio does not (the requirement belongs to the group you build), Slider does not,kui-otp-inputmarks only its first cell, andkui-segmentedexposes no required state.
Consumer-visible changes of @kikita-labs/ui 2.0 for Field.
- The classes are
KuiField,KuiInput,KuiInputGroup,KuiFieldAffix,KuiFieldAffixIconandKuiFieldAction(they had aComponentorDirectivesuffix);ng update @kikita-labs/uirenames the imports. KUI_FIELD_OPTIONSis removed andkuiProvideFieldOptionsis deprecated until 3.0: setdefaults.fieldthroughprovideKuiDefaultsorprovideKikitaUi({ defaults }). A nested provider now merges with its parent per property.kui-fieldexposes its required state asaria-requiredon the controls that support it, so snapshot tests of the rendered markup change.- Field styles moved into the
kui.componentslayer without::ng-deep: the field needskikita-ui.csslike every other component, and an unlayered application rule overrides it without raising specificity.