</> handleSubmit: UseFormHandleSubmit
This function will receive the form data if form validation is successful.
Props
| Name | Type | Description |
|---|---|---|
| SubmitHandler | (data: Object, e?: Event) => Promise<void> | A successful callback. |
| SubmitErrorHandler | (errors: Object, e?: Event) => Promise<void> | An error callback. |
-
disabledinputs will appear asundefinedvalues in form values. If you want to prevent users from updating an input and wish to retain the form value, you can usereadOnlyor disable the entire <fieldset />. Here is an example. -
handleSubmitfunction will not swallow errors that occurred inside your onSubmit callback, so we recommend you to try and catch inside async request and handle those errors gracefully for your customers. UsesetErrorinside the catch block to register a server-side error — this also ensuresformState.isSubmitSuccessfulis set tofalse.const onSubmit = async (data) => {// async request which may result errortry {// await fetch()} catch (e) {setError("root.serverError", {type: e.status,message: e.message,})}}return <form onSubmit={handleSubmit(onSubmit)} />
Examples:
Sync
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")} /><input {...register("lastName")} /><input type="email" {...register("email")} /><input type="submit" /></form>)}
Async
import { useForm } from "react-hook-form"const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))function App() {const {register,handleSubmit,formState: { errors },} = useForm()const onSubmit = async (data) => {await sleep(2000)if (data.username === "bill") {alert(JSON.stringify(data))} else {alert("There is an error")}}return (<form onSubmit={handleSubmit(onSubmit)}><label htmlFor="username">User Name</label><input placeholder="Bill" {...register("username")} /><input type="submit" /></form>)}
Resolver with transformed values
When a resolver (Zod, Yup, Joi, or custom) transforms the submitted data — so the output type differs from the field input type — use useForm's third generic, TTransformedValues, to tell TypeScript what handleSubmit will receive. Without it, the callback is typed as the input (field) type and you'll get errors accessing transformed properties.
import { useForm, SubmitHandler } from "react-hook-form"import { zodResolver } from "@hookform/resolvers/zod"import * as z from "zod"// Example using Zod — the same pattern applies to any resolver whose// output type differs from its input type (Yup, Joi, custom, etc.)const schema = z.object({emailOrPhone: z.string().trim(),}).transform(({ emailOrPhone }) => ({isEmail: emailOrPhone.includes("@"),isPhone: /^\d+$/.test(emailOrPhone),value: emailOrPhone,}))type FormInput = z.input<typeof schema> // { emailOrPhone: string }type FormOutput = z.output<typeof schema> // { isEmail: boolean; isPhone: boolean; value: string }export default function App() {// 1st generic = field/input type (drives register, watch, etc.)// 3rd generic = transformed output type (drives handleSubmit callback)const { register, handleSubmit } = useForm<FormInput, unknown, FormOutput>({resolver: zodResolver(schema),})const onSubmit: SubmitHandler<FormOutput> = (data) => {console.log(data.isEmail, data.isPhone, data.value)}return (<form onSubmit={handleSubmit(onSubmit)}><input {...register("emailOrPhone")} /><input type="submit" /></form>)}
Video
The following video tutorial explains the handleSubmit API in detail.
Thank you for your support
If you find React Hook Form to be useful in your project, please consider to star and support it.