Vize

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.

Open the interactive example

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
Validate a display name: initial state
Initial state
Validate a display name: state after the verified interactions
After the verified interactions

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.