Vize

use-form

Fully typed form state with validation, field arrays, and submission.

Package @vizejs/composable/use-form
Own the source vize lib pull composable:use-form
Runtime exports useForm
Gzip budget 7168 B

Usage

import { useForm } from "@vizejs/composable/use-form";

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
useForm state experimental safe stable reactive-scope web, server, worker, native, desktop, terminal AbortController, DOMException, structuredClone tryOnScopeDispose, validateStandardSchema

API

useForm

Fully typed form state with validation, field arrays, and submission. The value type is inferred from initialValues; every path is a template-literal key, so field("address.city") returns controls whose value is typed as the city's type and misspelled paths do not compile. Validation combines a Standard Schema v1 validator (Zod, Valibot, ArkType, … via the ~standard protocol), a whole-form validator, and per-field validators; all may be asynchronous. A newer validation aborts older ones through their signal and their results are discarded, so a slow check can never overwrite fresher errors. This composable owns the values. @vizejs/ui/form owns accessible error presentation (error summaries, focus management, native constraint validation); feed FormControls.errors into it to render them. Server rendering: pure state, no host access; validation never runs automatically during setup, so server and client render the same markup. Pending validations are aborted when the owning scope stops.

function useForm<Values extends object, Output = Values>( options: UseFormOptions<Values, Output>, ): FormControls<Values, Output>
const form = useForm({
  initialValues: { name: "", address: { city: "" }, tags: [] as string[] },
  validators: { name: (name) => (name ? undefined : "Required") },
  onSubmit: (values) => api.save(values),
});
const city = form.field("address.city"); // city.value: Ref<string>
const tags = form.fieldArray("tags");
tags.append("vue");

Types

FieldValidatorContext

Context passed to field validators.

Member Type Description
values Values Current form values (undefined for standalone fields).
path string Dotted path of the validated field.
signal AbortSignal Aborted when a newer validation supersedes this one.

UseFormOptions

Options for useForm.

Member Type Description
initialValues Values | (() => Values) Initial values, or a factory producing fresh initial values.
schema? StandardSchemaV1<NoInfer<Values>, Output> Standard Schema v1 validator for the whole form. Its output becomes the submitted value.
validate? NoInfer<FormValidator<Values>> Plain whole-form validator.
validators? NoInfer<FormFieldValidators<Values>> Plain per-field validators keyed by path.
validateOn? FormValidationTrigger When fields validate before the first submit.
revalidateOn? FormValidationTrigger When fields re-validate after the first submit.
onSubmit? (value: Output, context: { readonly signal: AbortSignal }) => unknown Default submit handler for FormControls.submit.

SetFieldValueOptions

Options for FormControls.setValue.

Member Type Description
touch? boolean Mark the field touched.
validate? boolean Validate the field after setting it.

FormFieldControls

Reactive controls for one field, returned by FormControls.field.

Member Type Description
path Path Dotted path of the field (also a suitable name attribute).
value WritableComputedRef<Value> Writable value bound to the form state (use with v-model).
errors ComputedRef<readonly string[]> Current error messages.
error ComputedRef<string | undefined> First error message.
dirty ComputedRef<boolean> Whether the value differs from its initial value.
touched ComputedRef<boolean> Whether the field was blurred or touched programmatically.
validating ComputedRef<boolean> Whether a validation of this field is pending.
onBlur () => void Mark the field touched (wire to blur); validates when configured.
validate () => Promise<boolean> Validate this field.
reset () => void Restore the initial value and clear errors and touched state.

FormArrayEntry

One entry of a field array, with a stable key for v-for.

Member Type Description
key number Stable key that follows the item through moves.
index number Current index.
path ${Path}.${number} Dotted path of the item, e.g. items.2.
value Item Current item value.

FormFieldArrayControls

Typed operations on an array field, returned by FormControls.fieldArray.

Member Type Description
entries ComputedRef<readonly FormArrayEntry<Item, Path>[]> Entries with stable keys.
append (...items: Item[]) => void Append items.
prepend (...items: Item[]) => void Prepend items.
insert (index: number, item: Item) => void Insert an item at index.
remove (index: number) => void Remove the item at index, shifting errors and touched state.
move (from: number, to: number) => void Move an item from one index to another, carrying its state along.
swap (first: number, second: number) => void Swap two items.
replace (items: readonly Item[]) => void Replace all items and reset their state.

FormControls

Reactive state and actions returned by useForm.

Member Type Description
values Ref<Values> Current values. Mutations are tracked (dirty state derives from them).
errors Readonly<ShallowRef<FormErrorRecord>> Current errors keyed by path; "" holds form-level errors.
valid ComputedRef<boolean> Whether no errors are currently recorded.
dirty ComputedRef<boolean> Whether any value differs from its initial value.
validating ComputedRef<boolean> Whether any validation is pending.
submitting Readonly<Ref<boolean>> Whether a submission is in progress.
submitCount Readonly<Ref<number>> Number of submit attempts.
field <Path extends FormPath<Values>>( path: Path, ) => FormFieldControls<FormPathValue<Values, Path>, Path> Typed controls for one field.
fieldArray <Path extends FormArrayPath<Values>>( path: Path, ) => FormFieldArrayControls<FormArrayItem<Values, Path>, Path> Typed operations for an array field.
getValue <Path extends FormPath<Values>>(path: Path) => FormPathValue<Values, Path> Read the value at a path.
setValue <Path extends FormPath<Values>>( path: Path, value: FormPathValue<Values, Path>, options?: SetFieldValueOptions, ) => void Write the value at a path.
setValues (values: Partial<Values>, options?: { readonly merge?: boolean }) => void Replace (or shallowly merge) the values without touching initial values.
isTouched (path: FormPath<Values>) => boolean Whether a field was touched.
setErrors (errors: FormErrors<Values>) => void Replace errors (for example with server-side errors).
clearErrors (path?: FormPath<Values> | "") => void Clear errors of one path, or all errors.
validate () => Promise<FormResult<Output>> Run every validator, aborting any older validation still in flight.
submit ( handler?: (value: Output, context: { readonly signal: AbortSignal }) => unknown, ) => Promise<FormResult<Output>> Validate and, when valid, call handler (or the onSubmit option). A newer submit aborts an older one's pending validation.
handleSubmit ( handler?: (value: Output, context: { readonly signal: AbortSignal }) => unknown, ) => (event?: Event) => Promise<FormResult<Output>> Create a submit event listener that prevents the native submission.
reset (values?: Values) => void Restore initial values (or install new ones) and clear all state.