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.
Props
| Prop | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Dot-separated path to this field within form.values. Supports nested paths (address.city) and array item paths (tags.0). |
form | NotFormInstance<any> | No | Explicit instance override. Takes priority over any <NotForm> ancestor. Required when used outside of <NotForm>. |
validateOn | Partial<Record<ValidationTrigger, boolean>> | No | Per-field overrides for validation triggers. Merged over the form-level config — only the keys you specify are changed. |
debounce | number | No | Debounce delay in milliseconds for input- and change-triggered validation. |
Slot props
| Prop | Type | Description |
|---|---|---|
path | string | The path passed to this field. |
value | any | Read-only snapshot of the current field value. Use v-model="form.values.fieldName" for binding — not this prop. |
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. |
validate | () => Promise<StandardSchemaV1.Result> | Manually triggers field validation. Useful for custom inputs that manage their own interaction events. |
events | { onBlur, onInput, onChange, onFocus } | Native DOM event handlers. Spread onto native inputs or bind individually to custom components. |
Usage
Spread events
The most common pattern. Spread all handlers at once onto a native input.
Bind individual events
When your component uses different event names, bind handlers individually.
<template>
<NotField
v-slot="{ events }"
path="country"
>
<label :for="path">
Country
<CustomSelect
:id="path"
v-model="form.values.country"
@close="events.onBlur"
@select="events.onChange"
/>
</label>
</NotField>
</template>
Nested paths
<template>
<NotField
v-slot="{ events, path }"
path="address.city"
>
<label :for="path">
City
<input
:id="path"
v-model="form.values.address.city"
v-bind="events"
>
</label>
<NotMessage :path="path" />
</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 — this field overrides it -->
<NotField
v-slot="{ events }"
path="username"
:validate-on="{ onInput: true }"
>
<label :for="path">
Username
<input
:id="path"
v-model="form.values.username"
v-bind="events"
>
</label>
</NotField>
</template>
<template>
<!-- Form has onBlur enabled — disable it for this checkbox -->
<NotField
v-slot="{ events }"
path="tos"
:validate-on="{ onBlur: false }"
>
<label :for="path">
<input
:id="path"
v-model="form.values.tos"
type="checkbox"
v-bind="events"
>
Accept terms
</label>
</NotField>
</template>
Validate on mount
<template>
<NotField
v-slot="{ events }"
path="email"
:validate-on="{ onMount: true }"
>
<label :for="path">
Email
<input
:id="path"
v-model="form.values.email"
v-bind="events"
>
</label>
</NotField>
</template>
Debounced validation
Add a delay between user input and validation firing. Useful for expensive validators or async checks like username availability.
<template>
<NotField
v-slot="{ events, isValidating }"
path="username"
:debounce="300"
>
<label :for="path">
Username
<input
:id="path"
v-model="form.values.username"
v-bind="events"
>
<span v-if="isValidating">Checking…</span>
</label>
</NotField>
</template>
Conditional UI from slot state
<template>
<NotField
v-slot="{ events, isTouched, errors, isDirty, isValidating, isValid }"
path="password"
>
<label :for="path">
Password
<input
:id="path"
v-model="form.values.password"
type="password"
v-bind="events"
>
</label>
<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
v-slot="{ events }"
:form="form"
path="search"
>
<label :for="path">
Search
<input
:id="path"
v-model="form.values.search"
v-bind="events"
>
</label>
</NotField>
</template>