From inputs to submit
handleSubmitwaits for validation, hands you parsed values, and reports submission state throughmeta.submitting.
- Read time
- ~4 minutes
- Builds on
- From schema to inputs
The demo binds two inputs (an email and a newsletter checkbox) and wires a submit handler that runs a 1.2-second simulated API call. Submit with a valid email and the button label switches to "Subscribing…" while the call runs, then a toast confirms the payload. Submit with an invalid email and focus pulls to the broken field automatically. The submit handler section below walks through the gating contract that produces that behavior.
Setting up the form
This page focuses on two helpers off the form: handleSubmit (the submit-wrapping factory) and meta (the form's reactive status board). Hoist the schema and save the form:
import { useForm } from 'attaform/zod'
import { z } from 'zod'
const schema = z.object({
email: z.email(),
newsletter: z.boolean(),
})
const form = useForm({ schema })
The same form carries every helper from earlier pages (register, fields, values). Only handleSubmit and meta are new here.
The submit handler
handleSubmit(onSubmit, onError?) returns a function you bind to <form @submit>. The wrapper calls preventDefault internally, so the .prevent modifier on the template is unnecessary. When the wrapped handler fires, it:
- Runs sync and async validation on every active path.
- Waits for pending async refinements before dispatching.
- Calls
onSubmit(values)only if validation passes.valuesis the parsed Zod output, fully typed. - Calls
onError(errors)if validation fails. By default, focus moves to the first invalid field.
const onSubmit = form.handleSubmit(
async (values) => {
await api.signup(values)
},
(errors) => {
console.log('Validation failed', errors)
}
)
<form @submit="onSubmit">…</form>
form.meta.submitting
While onSubmit is running, form.meta.submitting is true. Use it to disable the submit button or surface a spinner:
<button :disabled="form.meta.submitting" type="submit">
{{ form.meta.submitting ? 'Saving…' : 'Save' }}
</button>
submitting flips back to false when the callback resolves or rejects (handleSubmit catches the rejection and routes the failure to its error hook). The full meta surface (submissionAttempts, submitError, submitted, and the 22 inherited FieldState bits) lives on the meta page.
Where to next
handleSubmit: the full submit surface, including error handlers and event semantics.- The form: every method and property
useFormreturns.