useForm
Creates form state from a tinyval schema.
Signature
ts
function useForm<S extends Schema, V extends object>(schema: S, options: FormOptions<V>): Form<V, Infer<S>>Options
| Option | Type | Default | Description |
|---|---|---|---|
initial | V | — | Initial field values. Required. The type of form.values comes from it |
mode | 'blur' | 'input' | 'submit' | 'blur' | When to show field errors — see Errors |
debounce | number | 300 | Delay before async checks while typing, ms |
focusOnError | boolean | true | On a failed submit, focus the first field with an error (by the name attribute) |
extractErrors | (error) => errors | 422 response | How to get field errors from an exception in handleSubmit. By default understands Laravel 422 via axios and ofetch, and tinyval's ValidationError |
id | string | useId() | Base for field ids. Defaults to useId() in Vue 3.5+ — stable with SSR |
messages, labels, maxDepth | As in validate: language and field names for this form |
What it returns
A reactive object. Use it as a whole (form.errors.email) and don't destructure it — reactivity would be lost.
The form is provided to nested components: there useField('email'), useFieldArray('items'), useFormContext() and the TvField components work without passing the form.
| Field | Description |
|---|---|
values | Field values for v-model |
errors | Errors that should be shown now (according to mode) plus server errors: { email: '...', 'items.0.title': '...' } |
allErrors | All current errors, including ones not shown yet |
valid | The form is valid and there are no server errors |
dirty | Values differ from the initial ones |
changes | Only the changed fields — e.g. for PATCH, see Editing |
touched | Fields the user has left: { email: true } |
validating | An async check is running |
submitting | Submission (handleSubmit) is running |
submitted | The form was submitted at least once — after that all errors are shown |
submitCount | How many times submit was attempted |
submitSucceeded | The last submit succeeded |
data | Validated data (after trim, coerce…) or undefined |
| Method | Description |
|---|---|
touch(path) | Mark a field as touched — usually on @blur. touch('items') marks all nested fields |
handleSubmit(onValid, onInvalid?) | A @submit handler: prevents the page submit, validates the form and calls onValid(data) with validated data or onInvalid(errors) |
validate(paths?) | Validate the form and show all errors. With paths — only those fields, see Multi-step forms. Returns Promise<boolean> |
isDirty(path) | Whether a field has changed |
setValue(path, value), setValues(values) | Set one field / several fields |
setErrors(errors) | Show server errors: { email: '...' } or Laravel format { email: ['...'] } |
setFieldError(path, message?) | An error for one field; disappears when it changes. Without a message — remove |
clearErrors(path?) | Hide errors of a field or the whole form until the next blur / submit |
setTouched(path, value?) | Mark or unmark a field as touched |
resetField(path, value?) | Restore a field's initial value; with value — set a new initial value |
validateField(path) | Validate one field and show its error |
reset(values?) | Restore initial (or new) values and clear errors, touched, submitted. New values become the baseline for dirty |
bind(path) | modelValue, onUpdate:modelValue and onBlur — for UI library components |