Important: Typescript ^4.3 above is the recommended version to work with react hook form.
</> Resolver
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 { 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>)}
</> SubmitErrorHandler
import { useForm, SubmitHandler, SubmitErrorHandler } 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)const onError: SubmitErrorHandler<FormValues> = (errors) =>console.log(errors)return (<form onSubmit={handleSubmit(onSubmit, onError)}><input {...register("firstName", { required: true })} /><input {...register("lastName", { minLength: 2 })} /><input type="email" {...register("email")} /><input type="submit" /></form>)}
</> FormSubmitHandler
The type for the Form component's onSubmit prop — unlike SubmitHandler, the payload includes the raw FormData and formDataJson from the submission.
export type FormSubmitHandler<TTransformedValues> = (payload: {data: TTransformedValuesevent?: React.BaseSyntheticEventformData: FormDataformDataJson: stringmethod?: "post" | "put" | "delete"}) => unknown | Promise<unknown>
</> 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 = TFieldValues,> = {watch: UseFormWatch<TFieldValues>getValues: UseFormGetValues<TFieldValues>getFieldState: UseFormGetFieldState<TFieldValues>setError: UseFormSetError<TFieldValues>clearErrors: UseFormClearErrors<TFieldValues>setValue: UseFormSetValue<TFieldValues>setValues: UseFormSetValues<TFieldValues>trigger: UseFormTrigger<TFieldValues>formState: FormState<TFieldValues>resetField: UseFormResetField<TFieldValues>reset: UseFormReset<TFieldValues>resetDefaultValues: UseFormResetDefaultValues<TFieldValues>handleSubmit: UseFormHandleSubmit<TFieldValues, TTransformedValues>unregister: UseFormUnregister<TFieldValues>control: Control<TFieldValues, TContext, TTransformedValues>register: UseFormRegister<TFieldValues>setFocus: UseFormSetFocus<TFieldValues>subscribe: UseFormSubscribe<TFieldValues>}
</> UseFormProps
export type UseFormProps<TFieldValues extends FieldValues = FieldValues,TContext = any,TTransformedValues = TFieldValues,> = 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, TTransformedValues>context: TContextshouldFocusError: booleanshouldUnregister: booleanshouldUseNativeValidation: booleanprogressive: booleancriteriaMode: CriteriaModedelayError: numberformControl?: Omit<UseFormReturn<TFieldValues, TContext, TTransformedValues>,"formState">validate: ValidateForm<TFieldValues>}>
</> UseFormRegister
The type of register.
export type UseFormRegister<TFieldValues extends FieldValues> = <TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,>(name: TFieldName,options?: RegisterOptions<TFieldValues, TFieldName>) => UseFormRegisterReturn<TFieldName>
</> UseFormRegisterReturn
The shape returned by invoking register. Useful for typing a custom Input component that spreads {...register(name)}.
export type UseFormRegisterReturn<TFieldName extends InternalFieldName = InternalFieldName,> = {onChange: ChangeHandleronBlur: ChangeHandlerref: RefCallBackname: TFieldNamemin?: string | numbermax?: string | numbermaxLength?: numberminLength?: numberpattern?: stringrequired?: booleandisabled?: boolean}
</> UseFormUnregister
The type of unregister.
export type UseFormUnregister<TFieldValues extends FieldValues> = (name?:| FieldPath<TFieldValues>| FieldPath<TFieldValues>[]| readonly FieldPath<TFieldValues>[],options?: Omit<KeepStateOptions,| "keepIsSubmitted"| "keepSubmitCount"| "keepValues"| "keepDefaultValues"| "keepErrors"> & { keepValue?: boolean; keepDefaultValue?: boolean; keepError?: boolean }) => void
</> UseFormWatch
The type of watch. Overloaded — called with no argument, a single field name, an array of field names, or a callback for subscribing without triggering a re-render.
export type UseFormWatch<TFieldValues extends FieldValues> = {(): TFieldValues<TFieldNames extends readonly FieldPath<TFieldValues>[]>(names: readonly [...TFieldNames],defaultValue?: DeepPartial<TFieldValues>): FieldPathValues<TFieldValues, TFieldNames><TFieldName extends FieldPath<TFieldValues>>(name: TFieldName,defaultValue?: FieldPathValue<TFieldValues, TFieldName>): FieldPathValue<TFieldValues, TFieldName>(callback: WatchObserver<TFieldValues>,defaultValues?: DeepPartial<TFieldValues>): Subscription}
</> UseFormSubscribe
The type of subscribe — subscribe to formState changes without triggering a component re-render.
export type UseFormSubscribe<TFieldValues extends FieldValues> = <TFieldNames extends readonly FieldPath<TFieldValues>[],>(payload: {name?: readonly [...TFieldNames] | TFieldNames[number]formState?: Partial<ReadFormState>callback: (data: Partial<FormState<TFieldValues>> & {values: TFieldValuesname?: InternalFieldNametype?: EventType}) => voidexact?: boolean}) => () => void
</> UseFormHandleSubmit
The type of handleSubmit.
export type UseFormHandleSubmit<TFieldValues extends FieldValues,TTransformedValues = TFieldValues,> = (onValid: SubmitHandler<TTransformedValues>,onInvalid?: SubmitErrorHandler<TFieldValues>) => (e?: React.BaseSyntheticEvent) => Promise<void>
</> UseFormReset
The type of reset.
export type UseFormReset<TFieldValues extends FieldValues> = (values?:| DefaultValues<TFieldValues>| TFieldValues| ResetAction<TFieldValues>,keepStateOptions?: KeepStateOptions) => void
</> UseFormResetField
The type of resetField.
export type UseFormResetField<TFieldValues extends FieldValues> = <TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,>(name: TFieldName,options?: ResetFieldConfig<TFieldValues, TFieldName>) => void
</> UseFormResetDefaultValues
The type of resetDefaultValues.
export type UseFormResetDefaultValues<TFieldValues extends FieldValues> = (values: DefaultValues<TFieldValues> | TFieldValues,options?: Partial<Pick<KeepStateOptions, "keepDirty" | "keepIsValid">>) => void
</> UseFormSetError
The type of setError.
export type UseFormSetError<TFieldValues extends FieldValues> = (name:| FieldPath<TFieldValues>| `root.${string}`| "root"| "form"| `form.${string}`,error: ErrorOption,options?: {shouldFocus: boolean}) => void
</> UseFormClearErrors
The type of clearErrors.
export type UseFormClearErrors<TFieldValues extends FieldValues> = (name?:| FieldPath<TFieldValues>| FieldPath<TFieldValues>[]| readonly FieldPath<TFieldValues>[]| `root.${string}`| "root"| "form"| `form.${string}`) => void
</> UseFormSetValue
The type of setValue.
export type UseFormSetValue<TFieldValues extends FieldValues> = <TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,>(name: TFieldName,value: FieldPathValue<TFieldValues, TFieldName>,options?: SetValueConfig) => void
</> UseFormSetValues
The type of setValues.
export type UseFormSetValues<TFieldValues extends FieldValues> = (value: Partial<TFieldValues> | ((formValues: TFieldValues) => TFieldValues),options?: SetValueConfig) => void
</> UseFormSetFocus
The type of setFocus.
export type SetFocusOptions = Partial<{shouldSelect: boolean}>export type UseFormSetFocus<TFieldValues extends FieldValues> = <TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,>(name: TFieldName,options?: SetFocusOptions) => void
</> UseFormGetValues
The type of getValues. Overloaded — called with no argument, a single field name, or an array of field names.
export type GetValuesConfig = {dirtyFields?: booleantouchedFields?: boolean}export type UseFormGetValues<TFieldValues extends FieldValues> = {(name?: undefined, config?: GetValuesConfig): TFieldValues<TFieldName extends FieldPath<TFieldValues>>(name: TFieldName,config?: GetValuesConfig): FieldPathValue<TFieldValues, TFieldName><TFieldNames extends FieldPath<TFieldValues>[]>(names: readonly [...TFieldNames],config?: GetValuesConfig): [...FieldPathValues<TFieldValues, TFieldNames>]}
</> UseFormGetFieldState
The type of getFieldState.
export type UseFormGetFieldState<TFieldValues extends FieldValues> = <TFieldName extends FieldPath<TFieldValues>,>(name: TFieldName,formState?: FormState<TFieldValues>) => {invalid: booleanisDirty: booleanisTouched: booleanisValidating: booleanerror?: FieldError}
</> UseFormTrigger
The type of trigger.
export type TriggerConfig = Partial<{shouldFocus: boolean}>export type UseFormTrigger<TFieldValues extends FieldValues> = (name?:| FieldPath<TFieldValues>| FieldPath<TFieldValues>[]| readonly FieldPath<TFieldValues>[],options?: TriggerConfig) => Promise<boolean>
</> UseWatchProps
The props accepted by useWatch.
export type UseWatchProps<TFieldValues extends FieldValues = FieldValues> = {defaultValue?: unknowndisabled?: booleanname?:| FieldPath<TFieldValues>| FieldPath<TFieldValues>[]| readonly FieldPath<TFieldValues>[]control?: Control<TFieldValues>exact?: booleancompute?: (formValues: TFieldValues) => TFieldValues}
</> WatchProps
The props for the Watch render-prop component.
export type WatchProps<TFieldName extends WatchName<TFieldValues>,TFieldValues extends FieldValues = FieldValues,TContext = any,TTransformedValues = TFieldValues,TComputeValue = undefined,> = {control?: Control<TFieldValues, TContext, TTransformedValues>name?: TFieldNamedisabled?: booleanexact?: booleandefaultValue?: WatchDefaultValue<TFieldName, TFieldValues>compute?: (value: WatchValue<TFieldName, TFieldValues>) => TComputeValuerender: (value: WatchRenderValue<TFieldName, TFieldValues, TComputeValue>) => React.ReactNode | React.ReactNode[]}
</> UseFormStateProps
The props accepted by useFormState.
export type UseFormStateProps<TFieldValues extends FieldValues,TTransformedValues = TFieldValues,> = Partial<{control?: Control<TFieldValues, any, TTransformedValues>disabled?: booleanname?:| FieldPath<TFieldValues>| FieldPath<TFieldValues>[]| readonly FieldPath<TFieldValues>[]exact?: boolean}>
</> FormStateSubscribeProps
The props for the FormStateSubscribe render-prop component.
export type FormStateSubscribeProps<TFieldValues extends FieldValues,TTransformedValues = TFieldValues,> = UseFormStateProps<TFieldValues, TTransformedValues> & {render: (values: UseFormStateReturn<TFieldValues>) => React.ReactNode}
</> FormProviderProps
export type FormProviderProps<TFieldValues extends FieldValues = FieldValues,TContext = any,TTransformedValues = TFieldValues,> = {children: React.ReactNode | React.ReactNode[]} & UseFormReturn<TFieldValues, TContext, TTransformedValues>
</> FormProps
export type FormProps<TFieldValues extends FieldValues,TTransformedValues = TFieldValues,> = Omit<React.FormHTMLAttributes<HTMLFormElement>, "onError" | "onSubmit"> &Partial<{control: Control<TFieldValues, any, TTransformedValues>headers: Record<string, string>validateStatus: (status: number) => booleanonError: (payload:| { response: Response; error?: undefined }| { response?: undefined; error: unknown }) => voidonSuccess: ({ response }: { response: Response }) => voidonSubmit: FormSubmitHandler<TTransformedValues>method: "post" | "put" | "delete"children: React.ReactNode | React.ReactNode[]render: (props: {submit: (e?: React.FormEvent) => void}) => React.ReactNode | React.ReactNode[]encType:| "application/x-www-form-urlencoded"| "multipart/form-data"| "text/plain"| "application/json"}>
</> 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> & {disabled?: boolean})[]}
</> FieldArrayMethodProps
Focus options accepted as the second argument to append, prepend, and insert.
export type FieldArrayMethodProps = {shouldFocus?: booleanfocusIndex?: numberfocusName?: string}
</> UseFieldArrayProps
export type UseFieldArrayProps<TFieldValues extends FieldValues = FieldValues,TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,TKeyName extends string = 'id',TTransformedValues = TFieldValues,> = {name: TFieldArrayNamekeyName?: TKeyNamecontrol?: Control<TFieldValues, any, TTransformedValues>rules?: {validate?| Validate<FieldArray<TFieldValues, TFieldArrayName>[], TFieldValues>| Record<string,Validate<FieldArray<TFieldValues, TFieldArrayName>[], TFieldValues>>} & Pick<RegisterOptions<TFieldValues>,'maxLength' | 'minLength' | 'required'>shouldUnregister?: booleandisabled?: boolean}
</> FieldArrayProps
export type FieldArrayProps<TFieldValues extends FieldValues = FieldValues,TFieldArrayName extendsFieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,TKeyName extends string = "id",> = {render: (fieldArray: UseFieldArrayReturn<TFieldValues, TFieldArrayName, TKeyName>) => React.ReactElement} & UseFieldArrayProps<TFieldValues, TFieldArrayName, TKeyName>
</> ControllerRenderProps
The shape of the field object passed to Controller's render prop. Useful for typing a custom controlled input component.
export type ControllerRenderProps<TFieldValues extends FieldValues = FieldValues,TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,> = {onChange: (...event: any[]) => voidonBlur: Noopvalue: FieldPathValue<TFieldValues, TName>disabled?: booleanname: TNameref: RefCallBack}
</> ControllerFieldState
The shape of the fieldState object passed to Controller's render prop.
export type ControllerFieldState = {invalid: booleanisTouched: booleanisDirty: booleanisValidating: booleanerror?: FieldError}
</> 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>,TTransformedValues = TFieldValues,> = {name: TNamerules?: Omit<RegisterOptions<TFieldValues, TName>,"valueAsNumber" | "valueAsDate" | "setValueAs" | "disabled">shouldUnregister?: booleandefaultValue?: FieldPathValue<TFieldValues, TName>control?: Control<TFieldValues, any, TTransformedValues>disabled?: booleanexact?: boolean}
</> ControllerProps
export type ControllerProps<TFieldValues extends FieldValues = FieldValues,TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,TTransformedValues = TFieldValues,> = {render: ({field,fieldState,formState,}: {field: ControllerRenderProps<TFieldValues, TName>fieldState: ControllerFieldStateformState: UseFormStateReturn<TFieldValues>}) => React.ReactElement} & UseControllerProps<TFieldValues, TName, TTransformedValues>
</> 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> & GlobalErrorform?: GlobalError}
</> ErrorOption
The error object accepted by setError.
export type ErrorOption = {message?: Messagetype?: LiteralUnion<keyof RegisterOptions, string>types?: MultipleFieldErrors}
</> 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})
</> FormState
The type of formState, returned by useForm and useFormState.
export type FormState<TFieldValues extends FieldValues> = {isDirty: booleanisLoading: booleanisSubmitted: booleanisSubmitSuccessful: booleanisSubmitting: booleanisValidating: booleanisValid: booleandisabled: booleansubmitCount: numberdefaultValues?: undefined | Readonly<DeepPartial<TFieldValues>>dirtyFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>touchedFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>validatingFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>errors: FieldErrors<TFieldValues>isReady: boolean}
</> KeepStateOptions
Options accepted by reset and useForm's resetOptions, controlling which parts of form state survive the reset.
export type KeepStateOptions = Partial<{keepDirtyValues: booleankeepErrors: booleankeepDirty: booleankeepValues: booleankeepDefaultValues: booleankeepIsSubmitted: booleankeepIsSubmitSuccessful: booleankeepTouched: booleankeepIsValidating: booleankeepIsValid: booleankeepSubmitCount: booleankeepFieldsRef: boolean}>
</> 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 { useForm, NestedValue } from "react-hook-form"import { 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("select", 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.