Quickstart
This page walks through building a complete form from scratch. It covers the four components you will use in almost every form.
How it works
Create a form instance
useNotForm takes a schema and initial values. It returns the instance you work with throughout the form.
<script setup lang="ts">
import { useNotForm } from 'notform'
import { z } from 'zod'
const form = useNotForm({
schema: z.object({
email: z.string().email('Enter a valid email'),
password: z.string('Invalid input').min(8, 'At least 8 characters'),
}),
initialValues: { email: '', password: '' },
onSubmit: async (values) => {
// Called only when schema passes. values is typed.
await login(values)
},
})
onSubmit only runs when validation passes. If validation fails on submit, it is never called.
Wrap with <NotForm>
<NotForm> renders a <form> element and makes the instance available to all descendants through Vue's provide/inject. Pass the instance once here — you do not need to pass it to every field.
<template>
<NotForm :form="form" @submit="form.submit">
<NotField
v-slot="{ events,path }"
path="email"
>
<!-- Fields -->
</NotField>
</NotForm>
</template>
Bind @submit to form.submit. It calls event.preventDefault() when validation fails or when onSubmit is defined, so you never need to wire that up yourself.
Add fields with <NotField>
<NotField> is renderless. It tracks state for one field and hands it to the slot. Spread events onto any native input.
<template>
<NotField path="email" v-slot="{ events }">
<input v-model="form.values.email" type="email" v-bind="events" />
</NotField>
</template>
path— dot-separated path to the value inform.valuesv-modelbinds directly toform.values— no unwrappingv-bind="events"attachesonBlur,onInput,onChange,onFocus
Show errors with <NotMessage>
<NotMessage> renders the first error for a path. It renders nothing when there is no error.
<template>
<NotField path="email" v-slot="{ events }">
<input v-model="form.values.email" v-bind="events" />
<NotMessage path="email" />
</NotField>
</template>
It renders a <span> by default. Use as to change the tag, and pass any class or attribute as normal.
<NotMessage path="email" as="p" />