Skip to content

Form data ​

A form has three "versions" of the data and two sets of errors. Here is what lives where and how it changes while the form is filled in. Every value below is real tinyval-vue output.

ts
const Signup = object({
  name: pipe(string(), trim(), minLength(2)),
  email: pipe(string(), email()),
  age: optional(pipe(coerce.number(), min(18))),
});

const form = useForm(Signup, { initial: { name: '', email: '', age: '' } });

values, data and changes ​

FieldWhat's insideExampleUsed for
form.valuesWhat the user typed, as is{ name: ' Ivan ', email: 'ivan@mail.ru', age: '30' }v-model
form.dataValidated data after the schema: trim, coerce, no unknown keys. undefined while there are errors{ name: 'Ivan', email: 'ivan@mail.ru', age: 30 }Preview, calculations
data in handleSubmitThe same as form.data, at submit time{ name: 'Ivan', email: 'ivan@mail.ru', age: 30 }Sending to the server
form.changesOnly the changed fields, as typed (from values){ email: 'petr@mail.ru' }PATCH — see Editing

The type of values comes from initial (strings in inputs), the type of data from the schema (age: number).

errors and allErrors ​

FieldWhat's inside
form.allErrorsAll current schema and server errors — right away, even before the user typed anything
form.errorsOnly those that should be shown: for fields the user has left, all of them after submit. Plus server errors

The format is the same as errors in tinyval: dot path → text of the first error. More about paths and texts in Validation result.

How the state changes ​

A user fills in a sign-up form:

SteperrorsallErrorsvaliddirtysubmittedsubmitCountsubmitSucceededdata
1. Form opened{}name, email: Requiredfalsefalsefalse0falseundefined
2. Typed ' I' into name{}name: Must be at least 2 characters long, email: Requiredfalsetruefalse0falseundefined
3. Left the name fieldname: Must be at least 2 characters longas in step 2falsetruefalse0falseundefined
4. Clicked "Submit"name, email — all errors visibleas in step 2falsetruetrue1falseundefined
5. Fixed it, the server answered 422email: The email has already been taken.samefalsetruetrue2false{ name: 'Ivan', … }
6. Changed the email, submitted{}{}truefalsetrue3true{ name: 'Ivan', email: 'petr@mail.ru', age: 30 }

What the table shows:

  • Errors are computed right away (allErrors in step 1) but shown when the user leaves a field or clicks "Submit".
  • A server error goes into errors and makes valid false, but data stays — the data did pass the schema. The error disappears when the user changes that field.
  • After a successful submit dirty is false again and changes is empty: the current values count as saved.

What handleSubmit receives ​

Only if the form is valid, and only the validated data — after trim and coerce:

ts
// form.values: { name: ' Ivan ', email: 'petr@mail.ru', age: '30' }
const submit = form.handleSubmit((data) => {
  data; // { name: 'Ivan', email: 'petr@mail.ru', age: 30 }
});

The errors passed to onInvalid are the visible errors (form.errors) at submit time, i.e. all of them.

Other fields ​

FieldValue
touchedFields the user has left: { name: true }. Paths as in errors
validatingtrue while an async check is running
submittingtrue while the handleSubmit handler is running
idBase for field ids

Full list — useForm.

See also ​