Your first schema
Any Zod schema becomes a typed, reactive Attaform.
- Read time
- ~5 minutes
- Builds on
- Quick start
Type into any of the demo's four inputs (email, password, displayName, age) and watch the live form.values JSON below the form update in real time. form.values is the reactive view of the form data that useForm returns, paths and types straight from the schema you handed in. The What Attaform reads section below traces each Zod construct in the demo to its form behavior.
What Attaform reads
useForm is Attaform's entry point. Hand it a Zod schema and it returns a reactive form carrying every helper a template needs: a per-input binding factory, a per-field state map, and the live parsed values. Save the return value and reach for the pieces by name:
import { useForm } from 'attaform/zod'
import { z } from 'zod'
const schema = z.object({
email: z.email(),
password: z.string().min(8),
displayName: z.string().min(2).optional(),
age: z.number().int().min(13),
})
const form = useForm({ schema })
Object fields become reactive paths on form.values; nested objects become nested paths; refinements become per-field validators surfaced through form.fields.
The schema above covers most of what a real signup form needs:
emailandpasswordare required strings. Attaform stores''as the default, soform.values.emailstarts as''and updates as the user types.displayNameis optional. Storage still starts at''; the.optional()flag lets the field's empty string pass schema parsing at submit time.ageis a required number. Storage starts at0; themin(13)refinement runs every time the field validates and shows up onform.fields.age.errors.
Defaults from the schema
You don't redeclare defaults when you call useForm. Attaform reads them from the schema: '' for strings, 0 for numbers, false for booleans, [] for arrays, {} for objects. Override per field with defaultValues:
const form = useForm({
schema,
defaultValues: {
age: 18,
displayName: 'Anonymous',
},
})
Overrides are partial. Fields you don't mention pick up the schema's own default.
Where to next
- From schema to inputs: bind the schema to native inputs with
register+v-register. - The form: every property
useFormreturns.