---
title: "Introduction"
description: "NotForm is a headless, schema-driven form library for Vue 3 and Nuxt. See what it does, what it leaves to you, and where to start."
canonical_url: "https://notformdocs.vercel.app/docs/getting-started/introduction"
---

> Index of every page on this site: [llms.txt](https://notformdocs.vercel.app/llms.txt)

NotForm manages form state for Vue 3 and Nuxt. You describe your data with a schema, NotForm turns it into a typed reactive form, and you keep full control of the markup and styling.

<code-collapse>

```vue
<script setup lang="ts">
import { Field, FieldError, Form, useForm } from 'notform'
import { z } from 'zod'

const form = useForm({
  initialValues: { email: '', message: '' },
  async onSubmit(data) {
    await fetch('/api/contact', {
      body: JSON.stringify(data),
      headers: { 'content-type': 'application/json' },
      method: 'POST',
    })
  },
  schema: z.object({
    email: z.email('Enter a valid email address.'),
    message: z.string().min(10, 'Write at least 10 characters.'),
  }),
})
</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>

    <Field
      v-slot="{ field }"
      :field="form.field('message')"
    >
      <label :for="field.path">Message</label>

      <textarea
        :id="field.path"
        v-model="field.model"
        v-bind="field.events"
      />

      <FieldError :errors="field" />
    </Field>

    <button
      type="submit"
      :disabled="form.isSubmitting"
    >
      Send
    </button>
  </Form>
</template>
```

</code-collapse>

## What you get

- **Types from your schema.** Field paths, field values, `form.values`, and the data passed to `onSubmit` are all inferred. A mistyped path is a compile error.
- **Validation you can tune.** Choose, per field, whether blur, change, or input triggers validation, whether errors clear eagerly, and how long to debounce.
- **Stable fields.** `form.field(path)` always returns the same instance for the same path, so touched state and pending validation survive re-renders.
- **Repeatable sections.** Array fields give every item a stable identity and keep errors attached to the right item when you add, remove, move, or swap.
- **Plain, reactive state.** `isDirty`, `isSubmitting`, `isValidating`, and the rest are ordinary reactive properties. There is nothing to subscribe to.
- **Any validator.** Zod, Valibot, ArkType, or any other library that implements [Standard Schema](https://standardschema.dev).

## What NotForm leaves to you

- **UI.** NotForm renders a native `<form>` and nothing else. Inputs, labels, layout, and styling are yours, or your component library's.
- **Validation rules.** Rules are written in your schema, not in NotForm.
- **Networking.** `onSubmit` receives validated data. How you send it is up to you.
- **Global state.** Every `useForm` call creates an independent form. There is no store to configure.

## Packages

<table>
<thead>
  <tr>
    <th>
      Package
    </th>
    
    <th>
      Use it for
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        notform
      </code>
    </td>
    
    <td>
      Vue 3 and Vite applications. Import components and <code>
        useForm
      </code>
      
       explicitly.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @notform/nuxt
      </code>
    </td>
    
    <td>
      Nuxt 4 applications. Registers the same components and <code>
        useForm
      </code>
      
       as auto-imports.
    </td>
  </tr>
</tbody>
</table>

<note>

These docs describe NotForm v4. If your project uses NotForm 3.x, start with the [v3 migration guide](https://notformdocs.vercel.app/docs/migrations/notform-v3).

</note>

## How this docs is organized

<card-group>
<app-card title="Getting started" to="/docs/getting-started/installation">

Install NotForm, build your first form, and learn the mental model.

</app-card>

<app-card title="Guides" to="/docs/guides/binding-inputs">

Task-oriented explanations of binding inputs, validation, errors, submission, state, and arrays.

</app-card>

<app-card title="Recipes" to="/docs/recipes/server-errors">

Complete solutions to common problems such as server errors, async checks, and multi-step forms.

</app-card>

<app-card title="Reference" to="/docs/components/form">

Exact contracts for components, `useForm`, and every public type.

</app-card>
</card-group>

## Suggested reading order

1. [Installation](https://notformdocs.vercel.app/docs/getting-started/installation)
2. [Quickstart](https://notformdocs.vercel.app/docs/getting-started/quickstart)
3. [Core concepts](https://notformdocs.vercel.app/docs/getting-started/core-concepts)
4. [Binding inputs](https://notformdocs.vercel.app/docs/guides/binding-inputs) and [Validation](https://notformdocs.vercel.app/docs/guides/validation)
5. Whatever your form needs next: [errors](https://notformdocs.vercel.app/docs/guides/errors), [array fields](https://notformdocs.vercel.app/docs/guides/array-fields), or a [recipe](https://notformdocs.vercel.app/docs/recipes/server-errors)

Building with an AI coding assistant? See [Working with AI](https://notformdocs.vercel.app/docs/ai/working-with-ai).

## Sitemap

See the full [sitemap](https://notformdocs.vercel.app/sitemap.md) for all pages.
