fn

useForm

v0.0.14testeddemo

Headless, performant form state management. Holds reactive values, flat path-keyed errors/touched maps, derived meta, and a full set of mutation/validation/submit/reset helpers. Validation accepts a Standard Schema (zod/valibot/arktype), a custom resolver, or per-field function validators.

Examples

ts
const { values, errors, handleSubmit } = useForm({
  initialValues: { email: '', age: 0 },
  schema: z.object({ email: z.string().email(), age: z.number().min(18) }),
});
const onSubmit = handleSubmit((output) => save(output));
ts
// Inline binding with defineField
const form = useForm({ initialValues: { name: '' } });
const [name, nameProps] = form.defineField('name');
// <input v-model="name" v-bind="nameProps">

Demo

Loading demo…

Signature

ts
export function useForm<TInput extends object, TOutput = TInput>(
  options: UseFormOptions<TInput, TOutput> ={ ... }

Type Parameters

TInputextends object
TOutput= TInput

Parameters

ParameterTypeDescription
options?UseFormOptions<TInput, TOutput>Initial values, schema/resolver, and validation triggers

Returns

UseFormReturn<TInput, TOutput>The reactive form instance (also provided to descendant fields)
PropertyTypeDescription
valuesTInputReactive form values. Bind directly with v-model="values.path".
errorsComputedRef<FormErrors>Flat, reactive map of path → error messages.
metaComputedRef<FormMeta>Grouped reactive meta flags for the whole form.
isDirtyComputedRef<boolean>Whether any value differs from the initial snapshot.
isValidComputedRef<boolean>Whether the form has no errors.
isValidatingReadonly<Ref<boolean>>Whether a validation run is in flight.
isSubmittingReadonly<Ref<boolean>>Whether a submit is in flight.
submitCountReadonly<Ref<number>>Number of times submit has been attempted.
getFieldValue<P extends FieldPath<TInput>>(path: P) => FieldPathValue<TInput, P>Read a field value by path.
getError(path: FieldPath<TInput>) => string | undefinedThe first error message for a path, if any.
getErrors(path: FieldPath<TInput>) => string[]All error messages for a path (empty array when none).
isFieldDirty(path: FieldPath<TInput>) => booleanWhether a field differs from its initial snapshot.
isFieldTouched(path: FieldPath<TInput>) => booleanWhether a field has been touched.
isFieldValid(path: FieldPath<TInput>) => booleanWhether a field currently has no errors.
setFieldValue<P extends FieldPath<TInput>>( path: P, value: FieldPathValue<TInput, P>, options?: SetValueOptions, ) => voidWrite a field value by path.
setValues(values: PartialDeep<TInput>, options?: { merge?: boolean }) => voidMerge or replace multiple values at once.
setFieldError(path: FieldPath<TInput>, message: string | string[] | null) => voidSet or clear (with null) a field's error messages.
setErrors(errors: FormErrors) => voidReplace the entire error map.
setFieldTouched(path: FieldPath<TInput>, touched?: boolean) => voidMark a field touched/untouched.
setTouched(touched?: boolean) => voidMark all known fields touched/untouched.
validate() => Promise<FormValidationResult<TOutput>>Validate the whole form.
validateField(path: FieldPath<TInput>) => Promise<FieldValidationResultDetail>Validate a single field (runs the pipeline, updates that field's errors).
resetForm(state?: FormResetState<TInput>) => voidReset the form to its initial (or provided) state.
resetField<P extends FieldPath<TInput>>(path: P, value?: FieldPathValue<TInput, P>) => voidReset a single field to its initial (or provided) value.
handleSubmit( onValid: SubmissionHandler<TOutput>, onInvalid?: InvalidSubmissionHandler, ) => (event?: Event) => Promise<void>Wrap a submit callback: validates, then calls onValid with typed output (or onInvalid with the error map).
handleReset(event?: Event) => voidReset handler suitable for a <form>'s reset event.
defineField<P extends FieldPath<TInput>>( path: P, options?: DefineFieldOptions<FieldPathValue<TInput, P>, TInput>, ) => [Ref<FieldPathValue<TInput, P>>, ComputedRef<FieldBindingProps>]Bind a field inline: returns [model, props] for v-model + v-bind.
formProps{ onSubmit: (event: Event) => void; onReset: (event: Event) => void; novalidate: boolean; }Props to spread on the <form> element (@submit/@reset/novalidate).
_registerValidator(path: string, validator: FieldValidator) => void
_unregisterValidator(path: string, validator: FieldValidator) => void
_shouldValidate(trigger: Exclude<ValidationTrigger, 'manual'>) => boolean
_remapFieldPaths(basePath: string, indexMap: (index: number) => number | null) => void