Installation
NotForm ships as two packages that expose the same API.
| Package | Use it for |
|---|---|
notform | Vue 3 and Vite applications. |
@notform/nuxt | Nuxt 4 applications. Adds auto-imports for the same API. |
Requirements
- Vue 3.5 or later (declared as a peer dependency of
notform). - Nuxt 4 or later when using
@notform/nuxt. - A Standard Schema-compatible validator, installed separately. The examples use Zod.
- Node.js 24 or later. Depending on your package manager or environment settings, an older version may warn or fail.
Vue and Vite
Install notform and a validator:
pnpm add notform zod
npm install notform zod
yarn add notform zod
bun add notform zod
NotForm needs no Vue plugin and no global registration. Import what you use:
import { ArrayField, Field, FieldError, Form, useForm } from 'notform'
Nuxt
Install the module and a validator:
pnpm add @notform/nuxt zod
npm install @notform/nuxt zod
yarn add @notform/nuxt zod
bun add @notform/nuxt zod
Register the module, then restart the dev server:
export default defineNuxtConfig({
modules: ['@notform/nuxt'],
})
useForm, Form, Field, ArrayField, and FieldError are now auto-imported. See the Nuxt module guide for aliases and type imports.
notform so they work anywhere. In a Nuxt project, delete the import ... from 'notform' line and keep the rest.Choose a validator
NotForm accepts any object schema that implements Standard Schema. It does not bundle a validator and does not translate rules between libraries. Switching validators changes only the schema.
import { z } from 'zod'
const schema = z.object({
email: z.email('Enter a valid email address.'),
})
import * as v from 'valibot'
const schema = v.object({
email: v.pipe(v.string(), v.email('Enter a valid email address.')),
})
import { type } from 'arktype'
const schema = type({
email: 'string.email',
})
z.email()). On Zod 3, write z.string().email() instead. Standard Schema support requires Zod 3.24 or later, and recent releases of Valibot and ArkType.The schema must be an object schema. A bare z.string() is rejected by TypeScript, because form values are always a keyed object.
Verify the install
Render this component. Submitting an empty field should show the message, and a valid email should log the data.
<script setup lang="ts">
import { Field, FieldError, Form, useForm } from 'notform'
import { z } from 'zod'
const form = useForm({
initialValues: { email: '' },
onSubmit: (data) => {
return console.log(data)
},
schema: z.object({
email: z.email('Enter a valid email address.')
}),
})
</script>
<template>
<Form :form="form">
<Field
v-slot="{ field }"
:field="form.field('email')"
>
<label :for="field.path">Email</label>
<input
:id="field.path"
v-model="field.model"
v-bind="field.events"
type="email"
>
<FieldError :errors="field" />
</Field>
<button type="submit">
Submit
</button>
</Form>
</template>
Next steps
Continue with the Quickstart.