How it works
Schema alchemy in three steps
No field arrays. No register() calls. Your Zod schema is the single source of truth.
Step 1
Define your schema
const schema = z.object({
username: z.string().min(2),
role: z.enum(["dev", "design"]),
terms: z.boolean(),
});Step 2
Create the form
const { Form, Field } = createForm({
schema,
adapter: shadcnAdapter,
action: signupAction,
});Step 3
Render fields
<Form className="space-y-4">
{/* Fields auto-render from schema */}
<button type="submit">Submit</button>
</Form>
Live demo
Watch your schema become a form
This form is rendered entirely from the Zod schema on the left. Try submitting — or type 'taken' as username to see field errors.
schema.ts
const demoSchema = z.object({
username: z.string().min(2),
email: z.email(),
role: z.enum(["developer", "designer", "manager"]),
terms: z.boolean(),
});rendered form
Features
Everything you need, nothing you don't
Form libraries shouldn't require a PhD in useEffect. Formura gets out of your way.
Widgets
Inferred from your schema
Formura reads Zod types and metadata to pick the right widget. Override when you need to.
text
z.string()
password
.describe("widget:password")
otp
.describe("widget:otp")
number
z.number()
select
z.enum([...])
multiSelect
z.array(z.enum([...]))
textarea
.describe("widget:textarea")
checkbox
z.boolean()