handleSubmit

A submit handler that waits for validation, hands you parsed values, and routes rejections through onError.

Category
Return method
Signature
handleSubmit(onSubmit, onError?)
Returns
(event?) => Promise<void>

Submit the form without checking the terms box to watch the onError path fire: focus pulls to the broken field and the rejection alert lands. Check the box, fill the email, submit again to see onSubmit receive the parsed values. The dispatch contract section traces every step between the click and the callback.

handleSubmit Demo Open in playground

Signature

const submit = form.handleSubmit(
  async (values) => {
    /* onSubmit */
  },
  (errors) => {
    /* onError, optional */
  }
)

The return value is a function ready for <form @submit.prevent>. Call signature: (event?: Event) => Promise<void>.

The dispatch contract

When the returned handler fires:

  1. The form's submit count increments. form.meta.submissionAttempts lifts; the default getDisplayState heuristic starts surfacing errors for every field.
  2. Sync validation runs across every active path.
  3. Async refinements are awaited.
  4. If every refinement passes, onSubmit(values) is called with the parsed Zod output: .transform-aware, fully typed.
  5. If anything fails, focus pulls to the first invalid field and onError(errors) fires (when supplied).

While step 4 is awaiting your onSubmit callback, form.meta.submitting is true. It flips back when the callback resolves or rejects (handleSubmit catches and surfaces errors through onError).

Without onError

const submit = form.handleSubmit(async (values) => {
  await api.signup(values)
})

Skip onError when the default behavior (focus the first invalid field) is enough. Validation errors still surface through form.errors.<path>; the optional callback is for cross-field UI behavior like a toast or a console log.

Submission state

<button :disabled="form.meta.submitting" type="submit">
  {{ form.meta.submitting ? 'Saving…' : 'Save' }}
</button>

form.meta.submitting is the reactive flag while the onSubmit callback runs.

Where to next