NotForm

The root form component that provides context and handles submit/reset events.

<NotForm> is the root component that wraps your form. It provides the form instance to all descendant field components via Vue's provide/inject, so you don't need to pass a form prop to every <NotField> and <NotArrayField> individually, and it wires up the native submit and reset events on your behalf.

<NotForm> is a convenience, not a requirement. Every field component also accepts an explicit form prop, which takes priority over <NotForm>'s context and is required if you render fields without a <NotForm> ancestor at all.

Under the hood, <NotForm> renders a native <form> element, and it automatically:

  • Prevents the browser's default full-page navigation on submit and default field-clearing on reset — both would otherwise happen before any of your own logic runs, so this hands control back to you.
  • Provides the form instance to descendant <NotField> and <NotArrayField> components.

Because the underlying element is native, it does not clear validation errors or restore values by itself — that's what form.reset() does. <NotForm> only stops the browser from doing its own, separate reset first. This is why the usage example below still binds @submit="form.submit" and @reset="form.reset()" explicitly: <NotForm> clears the way for those calls to run, but doesn't make them for you.

Because it's still a real <form> element, other native behavior keeps working as expected:

  • Native form attributes like action, method, and enctype can be set directly on <NotForm> and pass through.
  • Submitting with the keyboard (pressing Enter in a text field) and assistive technology both work the same as with a plain <form>.
  • Native HTML validation attributes (required, pattern, minlength, and so on) still trigger the browser's built-in validation UI alongside NotForm's own. If you only want NotForm's validation messages to show, add novalidate to suppress the browser's.

Usage

A typical form setup involves passing a form instance to <NotForm> via the form prop, then wrapping your fields in its default slot.

<script setup lang="ts">
import { NotForm, useNotForm } from 'notform'
import { z } from 'zod'

const schema = z.object({
  email: z.email('Invalid email'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
})

const form = useNotForm({
  onSubmit(values) {
    console.log('Form submitted:', values)
  },
  schema,
})
</script>

<template>
  <NotForm
    :form="form"
    @submit="form.submit"
    @reset="form.reset()"
  >
    <!-- Form fields go here -->
    <button
      type="submit"
      :disabled="form.isSubmitting"
    >
      Submit
    </button>

    <button type="reset">
      Reset
    </button>
  </NotForm>
</template>

API

Props

form
NotFormAPI<TSchema> required
Form instance provided to descendant field components.

This is the same instance returned by useNotForm. <NotForm> makes it available to every <NotField> and <NotArrayField> beneath it, without needing to repeat it as a prop on each one.

Slots

default

The default slot for housing your form fields.

<template>
  <NotForm
    :form="form"
    @submit="form.submit"
    @reset="form.reset()"
  >
    <!-- Form fields go here -->
  </NotForm>
</template>
Unlike <NotField> and <NotArrayField>, this slot receives no slot props — there's no v-slot to bind here. <NotForm> only provides the form instance to descendants via context; to read form-level state like form.isSubmitting or form.isValid inside the slot, reference the form instance directly, as shown in the Usage example above.