21

Quickstart

Build a fully typed login form with validation in minutes.

This guide walks you through building a simple login form using the useNotForm composable and NotForm's headless components.

Demo

Here is the login form we will be building. Try submitting the form empty, or typing an invalid email to see the validation in action.

Step-by-step

Define the Schema

First, define your validation schema using a Standard Schema compliant library (we use zod in this example). This acts as the single source of truth for both your form's data shape and its validation rules.

import { z } from 'zod'

const schema = z.object({
  email: z.email('Enter a valid email'),
  password: z.string('Invalid input').min(8, 'At least 8 characters'),
})

Initialize the Form

Use the useNotForm composable to create your form instance. Pass in the schema and define an onSubmit handler.

const form = useNotForm({
  async onSubmit(data) {
    // `data` is fully typed as { email: string, password: string }
    console.log('Form submitted:', data)
  },
  schema,
})

Render the Form

Use the <NotForm> component to wrap your form. It automatically handles the native submit and reset events, preventing default browser behavior.

<template>
  <NotForm
    :form="form"
    @submit="form.submit"
    @reset="form.reset()"
  >
    <!-- Fields will go here -->

    <button
      type="submit"
      :disabled="form.isSubmitting.value"
    >
      Submit
    </button>
  </NotForm>
</template>

Connect the Fields

Use the <NotField> component for each field. It exposes an events object that you bind to your native <input> (which sets up blur and input listeners), and the path which serves as a stable ID.

<NotField v-slot="{ events, path }" path="email">
  <div>
    <label :for="path">Email</label>
    <input
      :id="path"
      v-model="form.values.email"
      v-bind="events"
      type="email"
    />
    <NotMessage :path="path" />
  </div>
</NotField>

The <NotMessage> component automatically displays the first validation error for the given path. If there are no errors, it renders nothing.

Next Steps

You now have a fully typed, validating form! To learn more about how NotForm integrates into your Vue applications, check out the Components guide, or deep dive into Composables.