Skip to content

Errors ​

Errors are checked on every change but shown when it's time — so the user isn't scolded while still typing.

When errors are shown ​

modeA field error is visible
'blur' (default)After the user leaves the field (touch)
'input'As soon as the value changes, or after leaving the field
'submit'Only after a submit attempt

After the first submit attempt (handleSubmit or validate) all errors are visible regardless of the mode. All current errors, including hidden ones, are in form.allErrors.

ts
const form = useForm(Signup, { initial, mode: 'input' });

Server errors ​

If the submit handler throws an error with a Laravel 422 response (axios, ofetch), the errors are spread over the fields automatically — nothing to do. A field error disappears as soon as the user changes that field; editing other fields keeps it.

For another response format use the extractErrors option of useForm or call setErrors manually:

ts
// axios / ofetch: 422 is handled automatically
const submit = form.handleSubmit((data) => axios.post('/api/signup', data));

// fetch: no exception on 422 — call setErrors yourself
const submitFetch = form.handleSubmit(async (data) => {
  const res = await fetch('/api/signup', { method: 'POST', body: JSON.stringify(data) });
  if (res.status === 422) {
    const { errors } = await res.json(); // { email: ['The email has already been taken.'] }
    form.setErrors(errors);
    return;
  }
  form.reset();
});

Language and field names ​

Set for the form with the same options as in validate. For fully custom texts see custom lang file.

ts
import ru from 'tinyval/locales/ru';

const form = useForm(Signup, {
  initial: { name: '', email: '' },
  messages: { ...ru, required: 'Поле «{label}» обязательно' },
  labels: { name: 'Имя', email: 'Почта' },
});

Focus the first error ​

On a failed submit the focus moves to the first field with an error in markup order — fields are found by the name attribute, so they need name with the path (name="email", name="items.0.title"). useField sets it for you. Disable with focusOnError: false.

For custom logic there is onInvalid — it receives the visible errors:

ts
const submit = form.handleSubmit(save, (errors) => {
  toast.error(`Please fix ${Object.keys(errors).length} fields`);
});

See also ​