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> = {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> = Partial<{mode: ModereValidateMode: ModedefaultValues: DeepPartial<TFieldValues>resolver: Resolver<TFieldValues, TContext>context: TContextshouldFocusError: booleanshouldUnregister: booleancriteriaMode: "firstError" | "all"}>
</> UseFieldArrayReturn
export type UseFieldArrayReturn<TFieldValues extends FieldValues = FieldValues,TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,TKeyName extends string = "id"> = {swap: (indexA: number, indexB: number) => voidmove: (indexA: number, indexB: number) => voidprepend: (value:| Partial<FieldArray<TFieldValues, TFieldArrayName>>| Partial<FieldArray<TFieldValues, TFieldArrayName>>[],options?: FieldArrayMethodProps) => voidappend: (value:| Partial<FieldArray<TFieldValues, TFieldArrayName>>| Partial<FieldArray<TFieldValues, TFieldArrayName>>[],options?: FieldArrayMethodProps) => voidremove: (index?: number | number[]) => voidinsert: (index: number,value:| Partial<FieldArray<TFieldValues, TFieldArrayName>>| Partial<FieldArray<TFieldValues, TFieldArrayName>>[],options?: FieldArrayMethodProps) => voidupdate: (index: number,value: Partial<FieldArray<TFieldValues, TFieldArrayName>>) => voidreplace: (value:| Partial<FieldArray<TFieldValues, TFieldArrayName>>| Partial<FieldArray<TFieldValues, TFieldArrayName>>[]) => voidfields: FieldArrayWithId<TFieldValues, TFieldArrayName, TKeyName>[]}
</> UseFieldArrayProps
export type UseFieldArrayProps<TKeyName extends string = "id",TControl extends Control = Control> = {name: stringkeyName?: TKeyNamecontrol?: TControlrules?: Pick<RegisterOptions<TFieldValues>,"maxLength" | "minLength" | "validate" | "required">}
</> 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>}
</> FieldError
export type FieldError = {type: stringref?: 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 = {ref: RefmutationWatcher?: MutationWatcheroptions?: RadioOrCheckboxOption[]} & 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
function Field<TFieldValues extends FieldValues,TPath extends FieldPathByValue<TFieldValues, Date>>({ control, name }: { control: Control<TFieldValues>; name: TPath }) {const { field } = useController({control,name,})}
</> FieldValues
export type FieldValues = Record<string, any>
</> FieldArrayWithId
export type FieldArrayWithId<TFieldValues extends FieldValues = FieldValues,TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,TKeyName extends string = "id"> = FieldArray<TFieldValues, TFieldArrayName> & Record<TKeyName, string>
</> Mode
export type Mode = {onBlur: "onBlur"onChange: "onChange"onSubmit: "onSubmit"onTouched: "onTouched"all: "all"}
</> RegisterOptions
export type RegisterOptions = Partial<{required: Message | ValidationRule<boolean>min: ValidationRule<number | string>max: ValidationRule<number | string>maxLength: ValidationRule<number | string>minLength: ValidationRule<number | string>pattern: ValidationRule<RegExp>validate: Validate | Record<string, Validate>}>
</> FormStateProxy
export type FormStateProxy<TFieldValues extends FieldValues = FieldValues> = {isDirty: booleandirtyFields: Dirtied<TFieldValues>isSubmitted: booleansubmitCount: numbertouched: FieldNames<TFieldValues>isSubmitting: booleanisValid: booleanerrors: FieldErrors<TFieldValues>}
</> 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.