Skip to Content
DocsField Binding

Field Binding & Components

Formly provides two primary ways to register and bind input elements to the form state: the declarative <Field /> component and the useField() hook. Both methods ensure that only the individual input re-renders on value updates.


The <Field /> Component

The <Field /> component is a declarative wrapper that automatically connects standard HTML inputs to your form state. It manages label text, handles error displays, tracks touched states, and injects accessibility attributes.

Basic Usage

import { Form, Field, useForm } from "@explita/formly"; function MyForm() { const form = useForm({ defaultValues: { username: "" } }); return ( <Form use={form}> <Field name="username" label="Account Username" placeholder="Enter username" required render={(props, ctx) => ( <div className="input-group"> <input {...props} /> {ctx.touched && ctx.error && ( <span className="error">{ctx.error}</span> )} </div> )} /> </Form> ); }

Pre-bound Field Component (form.Field)

Instead of importing the global <Field /> component, you can use the pre-bound component exposed directly by your form instance. This removes the dependency on React context and makes your code cleaner:

const form = useForm({ defaultValues: { username: "" } }); return ( <Form use={form}> <form.Field name="username" label="Username" render={(props) => <input {...props} />} /> </Form> );

The useField Hook

The useField hook is ideal for building custom input components or integrating with complex third-party library fields (like Select components, date pickers, or rich text editors).

Hook Signature

const field = useField(namePath, options?);

Return Value Properties

The useField hook returns a FieldController object with the following properties:

PropertyTypeDescription
valueTThe current value of the field.
setValue(value: T) => voidSets the field value programmatically.
errorstring | undefinedThe active validation error message.
hasErrorbooleanFlag indicating if the field currently has a validation error.
touchedbooleanFlag indicating if the input has been focused and blurred.
dirtybooleanFlag indicating if the value differs from its initial default.
reset() => voidResets value, touched, and dirty states to initial values.
validate() => Promise<boolean>Triggers validation specifically for this field element.
focus() => voidProgrammatically focuses this field’s input element.
bind()() => objectReturns pre-bound event handlers (name, value, onChange, onBlur, and ARIA tags).
refIdstringA unique stable DOM reference ID for labels and aria-describedby bindings.

Hook Example

import { useField } from "@explita/formly"; function CustomTextInput({ name, label }: { name: string; label: string }) { const { value, setValue, error, touched, bind } = useField(name); return ( <div className="form-group"> <label>{label}</label> <input {...bind()} type="text" className={touched && error ? "border-red" : ""} /> {touched && error && <div className="error-msg">{error}</div>} </div> ); }

Choosing Between <Field /> and useField

Use this table to decide which approach fits your implementation:

Use CaseRecommendation
Simple input/select with standard HTML events<Field render={(props) => <input {...props} />} />
Fast prototyping & simple markup templates<Field /> component
Custom complex inputs (comboboxes, calendar picks)useField() custom hook
Reusable form UI library componentsuseField() custom hook
Advanced manual focus & programmatic verificationuseField() hook helpers

Input Normalization

In addition to field-level rendering, Formly supports Declarative Input Normalization at the form configuration level. This allows you to format and sanitize input values in real-time as the user types (e.g., stripping non-digits from phone numbers, capitalizing promo codes, or formatting credit card spaces).

Normalization runs automatically before committing the value to the form state, triggering validations, or notifying subscribers.

Example: Normalizing phone numbers and promo codes

To configure normalizers, pass a normalize object to useForm. Each key matches a field path and takes a function returning the normalized value:

import { Form, Field, useForm } from "@explita/formly"; function ProfileForm() { const form = useForm({ defaultValues: { phone: "", promoCode: "", }, normalize: { // 1. Clean phone input: strip non-digits and limit to 10 characters phone: (value, prevValue) => value.replace(/\D/g, "").slice(0, 10), // 2. Format promo code: force uppercase and trim whitespace promoCode: (value) => value.toUpperCase().trim(), }, }); return ( <Form use={form}> <Field name="phone" label="Phone Number" render={(props) => <input {...props} placeholder="Only digits allowed" />} /> <Field name="promoCode" label="Promo Code" render={(props) => <input {...props} />} /> </Form> ); }

Since the normalizer runs on every keystroke, the bound input value stays perfectly formatted in real-time, preventing users from entering invalid characters into your form state.

Last updated on