GitHub

NotField

Renderless field wrapper. Exposes per-field state and event handlers through its default slot.

<NotField> tracks validation, dirty state, and touched state for a single field. It renders nothing itself — everything is handed to the slot and you build the UI.

Props

path
string required
Dot-separated path to this field within form.values. Supports nested paths (address.city) and array item paths (tags.0).
validateOn
Partial<Record<ValidationTrigger, boolean>>
Per-field overrides for validation triggers. Merged over the form-level config — only the keys you specify are changed.
form
NotFormInstance<any>
Explicit instance override. Takes priority over any <NotForm> ancestor. Required when used outside of <NotForm>.
debounce
number
Debounce delay in milliseconds for input- and change-triggered validation.

Slot props

path
string
The path passed to this field.
value
any
Read-only snapshot of the current field value. Do not use with v-model — bind v-model to form.values.fieldName directly.
errors
StandardSchemaV1.Issue[]
All validation issues for this field from the last validation run.
isValid
boolean
true when this field has no errors.
isTouched
boolean
true after the user has blurred this field, or after the form has been submitted.
isDirty
boolean
true when the current value differs from the initial value.
isValidating
boolean
true while an async validator is running for this field specifically.
validate
() => Promise<StandardSchemaV1.Result>
Manually triggers field validation. Useful for custom inputs that manage their own interaction events.
events
{ onBlur, onInput, onChange, onFocus }
All event handlers combined. Spread onto any input with v-bind="events".
onBlur
() => void
Marks the field touched and triggers validation when onBlur is enabled.
onInput
() => void
Updates dirty state. In eager mode, re-validates while an error exists.
onChange
() => void
Updates dirty state. In eager mode, re-validates while an error exists.
onFocus
() => void
Triggers validation when onFocus is enabled.

Usage

Spread events

The most common pattern. Spread all handlers at once onto a native input.

isValid

Blur or type to see field states.

Bind individual events

When your component uses different event names, bind handlers individually.

<template>
  <NotField
    path="country"
    v-slot="{ onBlur, onChange }"
  >
    <CustomSelect
      v-model="form.values.country"
      @close="onBlur"
      @select="onChange"
    />
  </NotField>
</template>

Nested paths

<template>
  <NotField
    path="address.city"
    v-slot="{ events }"
  >
    <input
      v-model="form.values.address.city"
      v-bind="events"
    >
    <NotMessage
      path="address.city"
    />
  </NotField>
</template>

Per-field trigger override

Override only the keys you want to change. The rest inherit from the form config.

<template>
<!-- Form has onInput disabled, but this field validates on every keystroke -->
  <NotField
    path="username"
    :validateOn="{ onInput: true }"
    v-slot="{ events }"
  >
    <input
      v-model="form.values.username"
      v-bind="events"
    >
  </NotField>
</template>
<template>
<!-- Form has onBlur enabled, but disable it for this checkbox -->
  <NotField
    path="tos"
    :validateOn="{ onBlur: false }"
    v-slot="{ events }"
  >
    <input
      type="checkbox"
      v-model="form.values.tos"
      v-bind="events"
    >
  </NotField>
</template>

Validate on mount

<template>
  <NotField
    path="email"
    :validateOn="{ onMount: true }"
    v-slot="{ events }"
  >
    <input
      v-model="form.values.email"
      v-bind="events"
    >
  </NotField>
</template>

Conditional UI from slot state

<template>
  <NotField
    path="password"
    v-slot="{ events, isTouched, errors, isDirty, isValidating, isValid }"
  >
    <input
      v-model="form.values.password"
      type="password"
      v-bind="events"
    >
    <span v-if="isValidating">Checking…</span>
    <span
      v-else-if="isTouched && !isValid"
      class="text-error"
    >
      {{ errors[0].message }}
    </span>
    <span
      v-else-if="isDirty && isValid"
      class="text-success"
    >
      Looks good
    </span>
  </NotField>
</template>

Singleton — no <NotForm> ancestor

Pass :form directly when the field is used outside of a <NotForm>.

<template>
  <NotField
    :form="form"
    path="search"
    v-slot="{ events }"
  >
    <input
      v-model="form.values.search"
      v-bind="events"
    />
  </NotField>
</template>