Form Field Managed
v0.1.2`FormField` with its react-hook-form wiring already done — the control's value/onChange/onBlur/ref, the label association, and the error message.
FormField with its react-hook-form wiring already done — the control's
value/onChange/onBlur/ref, the label association, and the error message.
Use plain FormField when you are managing state yourself;
use this when the field belongs to a react-hook-form form.
Usage
The error message comes from the field's own validation state — there is no
error prop to pass, and no need to read formState.errors. label, hint,
required and className pass through to FormField.
control is optional; the field resolves it from the surrounding Form /
FormProvider context.
Typing in TypeScript
field.value is typed as the field name points at, so it spreads onto a
control without a cast. Getting that narrowing depends on how the generics are
supplied.
Passing control infers both type parameters and needs no annotation:
Taking control from context instead means naming the field type too:
Supplying only the first type argument — <FormFieldManaged<Values> name="email">
— does not narrow. TypeScript stops inferring the remaining parameters once
any is given explicitly, so TName falls back to its default and field.value
widens to a union of every field in the form. Prefer one of the two forms above.
Why a render prop
The one thing that genuinely differs between controls is the prop they report changes on. Native inputs take the field as-is:
Radix-backed controls (Select, Checkbox, Toggle) report through
onValueChange / onCheckedChange, so the caller maps that one prop:
Making that visible is deliberate — it is the difference that matters, and it cannot be typed if hidden behind a clone.
Why not register
register() returns an uncontrolled native input contract
({name, onChange, onBlur, ref}). It works on TextField and Textarea,
which render real <input> / <textarea> elements.
It does not work on Checkbox, Toggle or Select. Those are Radix-backed:
the ref would land on the trigger <button>, whose value is always "", and
Radix reports changes through onCheckedChange / onValueChange, never
onChange. The field would silently submit its default value with no type or
runtime error. FormFieldManaged uses useController, which works for all of
them.
The render prop also receives the field's state as a second argument
((field, fieldState) => …) if you need invalid, isDirty or isTouched.
Compositions
Open all 1 →Properties
FormFieldManaged props
| Prop | Type | Default | Description |
|---|---|---|---|
children* | (field: ManagedField<TFieldValues, TName>, fieldState: ControllerFieldState) => ReactNode | — | Renders the control from the wired field |
name* | string | — | Field path in the form values; infers the field's value type |
className | string | — | Additional class names to merge with the component root element |
control | Control<TFieldValues> | — | Form control; falls back to the surrounding `useFormContext()` when omitted |
hint | ReactNode | — | Supporting hint text; hidden while `error` is present |
label | ReactNode | — | Field label |
required | boolean | — | Shows a required marker next to the label |
rules | RegisterOptions<TFieldValues, TName> | — | Validation rules passed through to react-hook-form |
Also accepts the native attributes of its root element (className, aria-*, event handlers, …).
PartialArgsStillWiden props
No props of its own.