use-field
A standalone validated field, independent of any form.
| Package | @vizejs/composable/use-field |
| Own the source | vize lib pull composable:use-field |
| Runtime exports | useField |
| Gzip budget | 3328 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useField } from "@vizejs/composable/use-field";
Try it
Validate a display name
Validate a profile field on blur and expose visited, changed, error, and reset states.
What to observe: Enter Al and press Tab to see the validation message. Replace it with Ada and leave the field again to clear the error. Reset clears both the value and interaction state.
Destructure the returned refs before using them in a template. Wire onBlur to the native blur event. The error records the last blur; subsequent edits wait for another blur, so an empty recorded error does not promise that an unvalidated edit is ready. The example checks name length, not server availability; no validation runs during setup.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { useId } from "vue";
import { useField } from "@vizejs/composable/use-field";
const fieldId = useId();
const { value, error, dirty, touched, onBlur, reset } = useField("", {
name: "displayName",
validateOn: "blur",
rules: (name) => (name.trim().length >= 3 ? undefined : "Use at least three characters."),
});
</script>
<template>
<div class="composable-example">
<label :for="fieldId">Display name</label>
<input
:id="fieldId"
v-model="value"
autocomplete="nickname"
:aria-invalid="Boolean(error)"
:aria-describedby="`${fieldId}-help ${fieldId}-error`"
@blur="onBlur"
/>
<p :id="`${fieldId}-help`">
Use at least three characters. Validation runs when you leave the field. Further edits wait
for the next blur before validation.
</p>
<p :id="`${fieldId}-error`" role="status">
{{ error || (touched ? "No recorded validation error." : "Enter a display name.") }}
</p>
<output>Changed: {{ dirty ? "yes" : "no" }} · Visited: {{ touched ? "yes" : "no" }}</output>
<button type="button" @click="() => reset()">Reset name</button>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useField |
state | experimental | safe | stable | reactive-scope | web, server, worker, native, desktop, terminal | AbortController, DOMException, structuredClone |
isStandardSchema, tryOnScopeDispose, validateStandardSchema |
API
useField
A standalone validated field, independent of any form. Rules may be plain (a)synchronous validators or Standard Schema v1 validators (anything with a ~standard property). A newer validation aborts older ones through their signal, and stale results are ignored. With validateOn: "change" validation runs after each value change, never during setup, so server-rendered markup matches the first client render. For multi-field state use useForm. Server rendering: pure state; nothing validates during setup. Pending validations are aborted when the owning scope stops.
function useField<Value>( initialValue: Value | (() => Value), options: UseFieldOptions<NoInfer<Value>> = {}, ): FieldControls<Value>
const email = useField("", {
name: "email",
rules: [(value) => (value.includes("@") ? undefined : "Invalid email")],
});
Types
FieldRuleContext
Context passed to standalone field validators.
| Member | Type | Description |
|---|---|---|
signal |
AbortSignal |
Aborted when a newer validation supersedes this one. |
UseFieldOptions
Options for useField.
| Member | Type | Description |
|---|---|---|
rules? |
FieldRuleSource<Value> | readonly FieldRuleSource<Value>[] |
Validators run in order; their messages are concatenated. |
validateOn? |
FieldValidationTrigger |
When validation runs automatically. |
name? |
string |
Field name exposed for name attributes and error summaries. |
FieldControls
Reactive state and actions returned by useField.
| Member | Type | Description |
|---|---|---|
name |
string |
Field name. |
value |
Ref<Value> |
Writable value (use with v-model). |
errors |
Readonly<ShallowRef<readonly string[]>> |
Current error messages. |
error |
ComputedRef<string | undefined> |
First error message. |
valid |
ComputedRef<boolean> |
Whether no errors are recorded. |
dirty |
ComputedRef<boolean> |
Whether the value differs from the initial value. |
touched |
Readonly<Ref<boolean>> |
Whether the field was blurred. |
validating |
Readonly<Ref<boolean>> |
Whether a validation is pending. |
onBlur |
() => void |
Mark the field touched (wire to blur); validates when configured. |
validate |
() => Promise<boolean> |
Run every rule, aborting an older validation still in flight. |
setErrors |
(errors: readonly string[]) => void |
Replace errors (for example with server errors). |
reset |
(value?: Value) => void |
Restore the initial value (or install a new one) and clear state. |