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({
initialValues: { email: '', password: '' },
onSubmit: async (values) => {
// Called only when schema passes. values is typed.
await login(values)
},
schema: z.object({
email: z.email('Enter a valid email'),
password: z.string().min(8, 'At least 8 characters'),
}),
})
</script>
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"
>
<!-- fields and submit button -->
</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
v-slot="{ events }"
path="email"
>
<label :for="path">
Email
<input
:id="path"
v-model="form.values.email"
type="email"
v-bind="events"
>
</label>
</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
v-slot="{ events, path }"
path="email"
>
<label :for="path">
Email
<input
:id="path"
v-model="form.values.email"
v-bind="events"
>
</label>
<NotMessage :path="path" />
</NotField>
</template>