21

Migrating from NotForm v3

Update NotForm v3 code to v4: renamed APIs, explicit field instances, moved validation config, and array fields.

NotForm v4 changes the public Vue API. This guide updates forms written with the v3 names useNotForm, NotForm, NotField, NotArrayField, and NotMessage.

Check your installed version first. If notform in your package.json is 3.x, the rest of these docs describe the version you are migrating to.

1. Rename the APIs

NotForm v3NotForm v4
useNotFormuseForm
<NotForm><Form>
<NotField><Field>
<NotArrayField><ArrayField>
<NotMessage><FieldError>

The core package is still notform. For Nuxt, use @notform/nuxt. Older instructions may reference notform-nuxt, so replace that dependency. In Vue, update imports from notform. In Nuxt, the module auto-imports the v4 names.

Rename everywhere with a project-wide search and replace on whole words, then fix the structural changes below.

2. Pass explicit field instances

In v3, <NotForm> provided form context to descendants, so a field could be declared with only a path. In v4, Form renders the native form but provides no context. Create each field on the form instance and pass it to Field.

<template>
  <NotForm :form="form">
    <NotField
      v-slot="{ events, path }"
      path="email"
    >
      <input
        v-bind="events"
        :id="path"
        v-model="form.values.email"
        type="email"
        :name="path"
      >

      <NotMessage :path="path" />
    </NotField>
  </NotForm>
</template>

The v4 Field slot exposes one field object. Use field.model, field.events, field.path, and field.errors instead of the top-level slot props events, path, and errors. Binding field.model also replaces writing to form.values.email directly, though that still works.

3. Move validation config to the field

v3 field components accepted options such as validateOn, validationMode, and debounce as props. In v4, pass a FieldConfig as the second argument when the field is first created.

const username = form.field('username', {
  debounce: 300,
  validateOn: { input: true },
  validationMode: 'lazy',
})

The keys of validateOn are blur, change, and input. A field is cached by path, so later calls with different options do not replace the first. See Validation.

4. Update array fields

v3 NotArrayField was declared by path. In v4, create an explicit array field, and use item.id as the key.

<template>
  <ArrayField
    v-slot="{ arrayField }"
    :array-field="form.arrayField('todos')"
  >
    <div
      v-for="item in arrayField.items"
      :key="item.id"
    >
      <Field
        v-slot="{ field }"
        :field="item"
      >
        <input
          v-bind="field.events"
          :id="field.path"
          v-model="field.model"
          type="email"
          :name="field.path"
        >

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

      <button
        type="button"
        @click="arrayField.remove(item.index)"
      >
        Remove
      </button>
    </div>

    <button
      type="button"
      @click="arrayField.append('')"
    >
      Add
    </button>
  </ArrayField>
</template>

Each item provides index, path, field(), and arrayField() for nested values. Mutations are methods on arrayField. See Array fields.

5. Check the rest of the form

  • Form requires a form prop and does not inject it into descendants.
  • FieldError takes an issue array or a field-like value through errors. It no longer resolves a path from form context.
  • onSubmit remains a useForm option, and Form handles native submit and reset.
  • useForm returns the public API in useForm. Do not rely on instance members that are not listed there.

Migration checklist

  • Dependencies updated (notform, and @notform/nuxt instead of notform-nuxt).
  • All useNotForm, NotForm, NotField, NotArrayField, and NotMessage renamed.
  • Every Field receives :field="form.field(path)" instead of a path prop.
  • Slot props switched to field.model, field.events, field.path, and field.errors.
  • FieldError receives :errors="field".
  • Validation options moved into form.field(path, config).
  • Array fields use form.arrayField(path), item.id keys, and array methods.
  • Type check and lint pass. Mistyped paths are now compile errors.

Next steps

Copyright © 2026 NotForm
Published under MIT License