Quick start
A typed schema, validated inputs, a submit handler. The minimum viable form in five minutes.
- Time
- ~5 minutes
- You'll learn
- useForm + register + handleSubmit
Try the form below: clear the password and submit to watch focus pull to the broken field; submit with valid values to see the alert fire. Every behavior on screen comes from the Zod schema in code, which you'll see in the Build a form section next.
Build a form
Hand useForm a Zod schema and the reactive form comes back ready. This page reaches for three properties on the returned form: register for the input binding, handleSubmit for the submit gate, and fields for per-field error reads.
import { useForm } from 'attaform/zod'
import { z } from 'zod'
const schema = z.object({
email: z.email(),
password: z.string().min(8),
})
const form = useForm({ schema })
const onSubmit = form.handleSubmit((values) => {
// values is the parsed Zod output, fully typed.
alert(JSON.stringify(values, null, 2))
})
Bind inputs to schema paths with v-register:
<template>
<form @submit="onSubmit">
<input v-register="form.register('email')" />
<em v-if="form.fields.email.showErrors">{{ form.fields.email.firstError?.message }}</em>
<input v-register="form.register('password')" type="password" />
<em v-if="form.fields.password.showErrors">{{ form.fields.password.firstError?.message }}</em>
<button type="submit">Sign in</button>
</form>
</template>
form.register('email') returns what the v-register directive binds to. The directive handles the value read, the write, the coercion, and focus on invalid submit. Errors render via form.fields.<path>.firstError?.message, gated by form.fields.<path>.showErrors so the form doesn't yell on first paint.
What's next
- Your first schema: what Attaform reads from a Zod definition.
- The form: the full reactive surface returned by
useForm. - When validation runs: the moment errors appear.