Field
Composable form field container for native controls. The field owns the visual shell, label, floating outline, prefix/suffix slots, hint, required marker, disabled state, and error slot while the actual value stays on a native control directive such as input[fktInputText].
Import
import {FktFieldComponent} from "frakton-ng/field";Composition
Field composition patterns. A fkt-field wraps a native control directive such as
input[fktInputText]. The field owns the visual shell while the projected control owns value,
native attributes, and form integration.
Basic input
Basic text input. The field renders the label and outline while input[fktInputText] remains the
real form control, so native attributes and browser behavior stay available to the consumer.
Sizes
Field sizes provide predefined densities for compact filters, default forms, and larger touch targets. The size belongs to the field shell so future controls keep the same visual rhythm.
Prefix suffix
Prefix and suffix slots are projected with [fktFieldPrefix] and [fktFieldSuffix].
The field owns spacing around the slots, while the projected content can be any component or
directive such as icons, buttons, or tooltips.
Hint
Hints provide secondary guidance below the field. Use the hint input for plain text, project
[fktHintStart] when the message needs custom template content, or [fktHintEnd] for
right-aligned supporting metadata. Visible errors replace the start hint.
Your workspace will be available at acme.frakton.app.
Character count
Character count is opt-in through fktCharacterCount on a textual control.
The field renders the computed count in the hint end slot by default. Project
[fktHintEnd] to replace that default with custom supporting metadata.
Custom meta
Required marker
Required marker behavior. When requiredMarker is omitted, the field tries to infer the marker
from the projected control validation state. Pass [requiredMarker]="true" to force it on, or
[requiredMarker]="false" to hide it while keeping the validation rule active.
Hidden label
Hidden labels keep compact controls visually clean without dropping the accessible label. Use this for search boxes, table filters, command inputs, and other cases where the placeholder is visible but the control still needs a stable semantic name.
Forms
Form integration examples. The field reads state from the projected FktFieldControl; the consumer
keeps validation rules in the form model instead of passing disabled, touched, invalid, or required
flags into the field manually.
Signal forms
Signal Forms integration with Angular's [field] directive. The field reacts to value, touched,
invalid, disabled, required, and error state exposed by the projected control.
Reactive forms
Reactive Forms integration through formControlName. Programmatic updates, reset, disabled state,
and validation changes are read from the Angular control adapter instead of relying only on DOM
attributes.
Error handling
Error handling examples. By default, the field shows its error state when the projected control is invalid and touched. That default can be overridden for submit attempts, server-side validation, or custom form flows.
Manual error control
Manual error visibility through showError. When the input is defined, it replaces the default
invalid && touched rule for both the red border and the message area.
Custom error
Custom projected error content. When [fktError] content is provided, it replaces the automatic
error message while still using the field's visibility and spacing behavior.
Use a company e-mail address.
Automatic error messages
Automatic error messages with provideFktConfig(withFieldErrorMessages(...)). The resolver turns
normalized Signal Forms or Reactive Forms errors into the text rendered by each field.
export const appConfig: ApplicationConfig = {
providers: [
provideFktConfig(
withFieldErrorMessages(({errors}) => {
if (!errors) return null;
const first = errors.errors[0];
if (first.message) return first.message; // If field already has a message defined, returns it
if (first.kind === 'required') return 'Field is required';
if (first.kind === 'email') return 'Enter a valid email address';
if (first.kind === 'minLength') {
return `Use at least ${first.params['minLength']} characters`;
}
if (first.kind === 'maxLength') {
return `Use at most ${first.params['maxLength']} characters`;
}
return null;
})
)
]
}
Translated error messages
Translated error messages combine withI18nIntegration(...) and withFieldErrorMessages(...).
The field recomputes visible errors when the configured language source changes. recomputeOn
accepts a Signal, an Observable, or an array mixing Signals and Observables.
export const appConfig: ApplicationConfig = {
providers: [
provideFktConfig(
withI18nIntegration(() => {
const translateService = inject(TranslateService);
return {
recomputeOn: translateService.currentLanguage$,
translateFn: translateService.instant.bind(translateService),
};
}),
withFieldErrorMessages(({errors, t}) => {
if (!errors) return null;
const first = errors.errors[0];
if (first.message) return first.message;
if (first.kind === 'required') return t('errors.required');
if (first.kind === 'email') return t('errors.email');
if (first.kind === 'minLength') {
return t('errors.minLength', first.params);
}
if (first.kind === 'maxLength') {
return t('errors.maxLength', first.params);
}
return null;
})
)
]
}
withI18nIntegration(() => ({
recomputeOn: currentLanguage, // Signal
translateFn: translate,
}))
withI18nIntegration(() => ({
recomputeOn: translateService.onLangChange, // Observable
translateFn: translateService.instant.bind(translateService),
}))
withI18nIntegration(() => ({
recomputeOn: [currentLanguage, translateService.onLangChange], // Signal + Observable
translateFn: translateService.instant.bind(translateService),
}))