React Hook Form
Wire Luke UI fields to React Hook Form with Controller.
React Hook Form owns the form state, and Luke UI renders the controls.
Initialise the form
Call useForm with defaultValues and a resolver, and keep the result as form. React Hook Form
takes the form's value types from the Zod schema, so no hand-written type repeats it.
const schema = z.object({
email: z.email('Enter an email address in the form you@example.com.'),
name: z.string().min(1, 'Enter your name.'),
});
const form = useForm({
defaultValues: { email: '', name: '' },
resolver: zodResolver(schema),
});Integrate components
Wrap each control in Controller. Its render prop hands you field and fieldState. Pass
field.value, field.onChange, and field.onBlur to the control, and give field.ref to
inputRef.
A checkbox reads its value from isSelected.
TextField and Checkbox render a label, description, and error message around the control, so
inputRef is what reaches the input underneath. A primitive that renders the control itself, such
as ComboboxInput, takes field.ref on ref.
Validation
Read the message from fieldState.error and pass it to errorMessage. The message marks the field
invalid.
<Controller
control={form.control}
name="email"
render={({ field, fieldState }) => (
<TextField
errorMessage={fieldState.error?.message}
inputRef={field.ref}
label="Email"
onBlur={field.onBlur}
onChange={field.onChange}
validationBehavior="aria"
value={field.value}
/>
)}
/>Set validationBehavior="aria" on every field a Controller wraps. Read
Validation for why native behaviour blocks the submit
event before the library can run.
Focus the first invalid field
React Hook Form focuses the first invalid control after a failed submission, using the ref each
field registered. A field that never receives field.ref stays unfocused, and the person filling in
the form gets an error message without being taken to it.
Set shouldFocusError: false on useForm to turn this off.
Submitting data
Wrap the submit handler in form.handleSubmit. It runs the schema first, then calls the handler
with the values.
<form onSubmit={form.handleSubmit((values) => saveAccount(values))}>