Important: Typescript ^4.3 above is the recommended version to work with react hook form.
</> Resolver
import React from "react"import { useForm, Resolver } from "react-hook-form"type FormValues = {firstName: stringlastName: string}const resolver: Resolver<FormValues> = async (values) => {return {values: values.firstName ? values : {},errors: !values.firstName? {firstName: {type: "required",message: "This is required.",},}: {},}}export default function App() {const {register,handleSubmit,formState: { errors },} = useForm<FormValues>({ resolver })const onSubmit = handleSubmit((data) => console.log(data))return (<form onSubmit={onSubmit}><input {...register("firstName")} placeholder="Bill" />{errors?.firstName && <p>{errors.firstName.message}</p>}<input {...register("lastName")} placeholder="Luo" /><input type="submit" /></form>)}
</> SubmitHandler
import React from "react"import { useForm, SubmitHandler } from "react-hook-form"type FormValues = {firstName: stringlastName: stringemail: string}export default function App() {const { register, handleSubmit } = useForm<FormValues>()const onSubmit: SubmitHandler<FormValues> = (data) => console.log(data)return (<form onSubmit={handleSubmit(onSubmit)}><input {...register("firstName")} /><input {...register("lastName")} /><input type="email" {...register("email")} /><input type="submit" /></form>)}
</> Control
import { useForm, useWatch, Control } from "react-hook-form"type FormValues = {firstName: stringlastName: string}function IsolateReRender({ control }: { control: Control<FormValues> }) {const firstName = useWatch({control,name: "firstName",defaultValue: "default",})return <div>{firstName}</div>}export default function App() {const { register, control, handleSubmit } = useForm<FormValues>()const onSubmit = handleSubmit((data) => console.log(data))return (<form onSubmit={onSubmit}><input {...register("firstName")} /><input {...register("lastName")} /><IsolateReRender control={control} /><input type="submit" /></form>)}
</> UseFormReturn
export type UseFormReturn<TFieldValues extends FieldValues = FieldValues,TContext = any,TTransformedValues extends FieldValues | undefined = undefined,> = {watch: UseFormWatch<TFieldValues>getValues: UseFormGetValues<TFieldValues>getFieldState: UseFormGetFieldState<TFieldValues>setError: UseFormSetError<TFieldValues>clearErrors: UseFormClearErrors<TFieldValues>setValue: UseFormSetValue<TFieldValues>trigger: UseFormTrigger<TFieldValues>formState: FormState<TFieldValues>resetField: UseFormResetField<TFieldValues>reset: UseFormReset<TFieldValues>handleSubmit: UseFormHandleSubmit<TFieldValues>unregister: UseFormUnregister<TFieldValues>control: Control<TFieldValues, TContext>register: UseFormRegister<TFieldValues>setFocus: UseFormSetFocus<TFieldValues>}
</> UseFormProps
export type UseFormProps<TFieldValues extends FieldValues = FieldValues,TContext extends object = object,TTransformedValues extends FieldValues | undefined = undefined,> = Partial<{mode: Modedisabled: booleanreValidateMode: Exclude<Mode, "onTouched" | "all">defaultValues: DefaultValues<TFieldValues> | AsyncDefaultValues<TFieldValues>values: TFieldValueserrors: FieldErrors<TFieldValues>resetOptions: Parameters<UseFormReset<TFieldValues>>[1]resolver: Resolver<TFieldValues, TContext>context: TContextshouldFocusError: booleanshouldUnregister: booleanshouldUseNativeValidation: booleanprogressive: booleancriteriaMode: CriteriaModedelayError: number}>
</> UseFieldArrayReturn
export type UseFieldArrayReturn<TFieldValues extends FieldValues = FieldValues,TFieldArrayName extendsFieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,TKeyName extends string = "id",> = {swap: UseFieldArraySwapmove: UseFieldArrayMoveprepend: UseFieldArrayPrepend<TFieldValues, TFieldArrayName>append: UseFieldArrayAppend<TFieldValues, TFieldArrayName>remove: UseFieldArrayRemoveinsert: UseFieldArrayInsert<TFieldValues, TFieldArrayName>update: UseFieldArrayUpdate<TFieldValues, TFieldArrayName>replace: UseFieldArrayReplace<TFieldValues, TFieldArrayName>fields: FieldArrayWithId<TFieldValues, TFieldArrayName, TKeyName>[]}
</> UseFieldArrayProps
export type UseFieldArrayProps<TFieldValues extends FieldValues = FieldValues,TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,TKeyName extends string = 'id',> = {name: TFieldArrayNamekeyName?: TKeyNamecontrol?: Control<TFieldValues>rules?: {validate?| Validate<FieldArray<TFieldValues, TFieldArrayName>[], TFieldValues>| Record<string,Validate<FieldArray<TFieldValues, TFieldArrayName>[], TFieldValues>>} & Pick<RegisterOptions<TFieldValues>,'maxLength' | 'minLength' | 'required'>shouldUnregister?: boolean}
</> UseControllerReturn
export type UseControllerReturn<TFieldValues extends FieldValues = FieldValues,TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,> = {field: ControllerRenderProps<TFieldValues, TName>formState: UseFormStateReturn<TFieldValues>fieldState: ControllerFieldState}
</> UseControllerProps
export type UseControllerProps<TFieldValues extends FieldValues = FieldValues,TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,> = {name: TNamerules?: Omit<RegisterOptions<TFieldValues, TName>,"valueAsNumber" | "valueAsDate" | "setValueAs" | "disabled">shouldUnregister?: booleandefaultValue?: FieldPathValue<TFieldValues, TName>control?: Control<TFieldValues>disabled?: boolean}
</> FieldError
export type FieldError = {type: LiteralUnion<keyof RegisterOptions, string>root?: FieldErrorref?: Reftypes?: MultipleFieldErrorsmessage?: Message}
</> FieldErrors
export type FieldErrors<T extends FieldValues = FieldValues> = Partial<FieldValues extends IsAny<FieldValues>? any: FieldErrorsImpl<DeepRequired<T>>> & {root?: Record<string, GlobalError> & GlobalError}
</> Field
export type Field = {_f: {ref: Refname: InternalFieldNamerefs?: HTMLInputElement[]mount?: boolean} & RegisterOptions}
</> FieldPath
This type is useful when you define custom component's name
prop, and it will type check against your field path.
export type FieldPath<TFieldValues extends FieldValues> = Path<TFieldValues>
</> FieldPathByValue
This type will return union with all available paths that match the passed value
export type FieldPathByValue<TFieldValues extends FieldValues, TValue> = {[Key in FieldPath<TFieldValues>]: FieldPathValue<TFieldValues,Key> extends TValue? Key: never}[FieldPath<TFieldValues>]
</> FieldValues
export type FieldValues = Record<string, any>
</> FieldArrayWithId
export type FieldArrayWithId<TFieldValues extends FieldValues = FieldValues,TFieldArrayName extendsFieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,TKeyName extends string = "id",> = FieldArray<TFieldValues, TFieldArrayName> & Record<TKeyName, string>
</> Mode
export type ValidationMode = typeof VALIDATION_MODEexport type Mode = keyof ValidationMode
</> RegisterOptions
export type RegisterOptions<TFieldValues extends FieldValues = FieldValues,TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,> = Partial<{required: Message | ValidationRule<boolean>min: ValidationRule<number | string>max: ValidationRule<number | string>maxLength: ValidationRule<number>minLength: ValidationRule<number>validate:| Validate<FieldPathValue<TFieldValues, TFieldName>, TFieldValues>| Record<string,Validate<FieldPathValue<TFieldValues, TFieldName>, TFieldValues>>value: FieldPathValue<TFieldValues, TFieldName>setValueAs: (value: any) => anyshouldUnregister?: booleanonChange?: (event: any) => voidonBlur?: (event: any) => voiddisabled: booleandeps: FieldPath<TFieldValues> | FieldPath<TFieldValues>[]}> &(| {pattern?: ValidationRule<RegExp>valueAsNumber?: falsevalueAsDate?: false}| {pattern?: undefinedvalueAsNumber?: falsevalueAsDate?: true}| {pattern?: undefinedvalueAsNumber?: truevalueAsDate?: false})
</> FormStateProxy
export type FormStateProxy<TFieldValues extends FieldValues = FieldValues> = {isDirty: booleanisValidating: booleandirtyFields: FieldNamesMarkedBoolean<TFieldValues>touchedFields: FieldNamesMarkedBoolean<TFieldValues>validatingFields: FieldNamesMarkedBoolean<TFieldValues>errors: booleanisValid: boolean}
</> NestedValue (Deprecated at 7.33.0)
import React from "react"import { useForm, NestedValue } from "react-hook-form"import { Autocomplete, TextField, Select } from "@material-ui/core"import { Autocomplete } from "@material-ui/lab"type Option = {label: stringvalue: string}const options = [{ label: "Chocolate", value: "chocolate" },{ label: "Strawberry", value: "strawberry" },{ label: "Vanilla", value: "vanilla" },]export default function App() {const {register,handleSubmit,watch,setValue,formState: { errors },} = useForm<{autocomplete: NestedValue<Option[]>select: NestedValue<number[]>}>({defaultValues: { autocomplete: [], select: [] },})const onSubmit = handleSubmit((data) => console.log(data))React.useEffect(() => {register("autocomplete", {validate: (value) => value.length || "This is required.",})register("select", {validate: (value) => value.length || "This is required.",})}, [register])return (<form onSubmit={onSubmit}><Autocompleteoptions={options}getOptionLabel={(option: Option) => option.label}onChange={(e, options) => setValue("autocomplete", options)}renderInput={(params) => (<TextField{...params}error={Boolean(errors?.autocomplete)}helperText={errors?.autocomplete?.message}/>)}/><Selectvalue=""onChange={(e) => setValue("muiSelect", e.target.value as number[])}><MenuItem value={10}>Ten</MenuItem><MenuItem value={20}>Twenty</MenuItem></Select><input type="submit" /></form>)}
Thank you for your support
If you find React Hook Form to be useful in your project, please consider to star and support it.