useForm is a custom composition API function that allows you to group fields created by useField and aggregates their state. It should be used to create logical forms or custom form components similar to the <Form/> component which is just a consumer of useForm.

The most basic usage is where you have both useField and useForm at the same setup function:

import { useField, useForm } from 'vee-validate';
import * as yup from 'yup';

export default {
  setup() {
    const { value: email, errors } = useField('email', yup.string().email().required());

    return {

The useForm composable has very powerful type information and can be fully typed, for more information check the useForm typing tutorial

API Reference

The full signature of the useForm function looks like this:

interface FormOptions {
  validationSchema?: any; // A yup schema, or a Record<string, any> containing valid rules as `useField`
  initialValues?: Record<string, any>;
  initialErrors?: Record<string, string>; // a map of the form's initial error messages
  initialDirty?: Record<string, boolean>; // a map of the form's initial dirty fields
  initialTouched?: Record<string, boolean>; // a map of the form's initial touched fields
  validateOnMount?: boolean;

type useForm = (
  opts?: FormOptions
) => {
  errors: Record<string, string>; // first error message for each field
  isSubmitting: boolean; // if the form submission function is being run
  meta: FormMeta; // aggregate of the field's meta information
  values: Record<string, any>; // current form values
  setFieldError: (field: string, errorMessage: string) => void; // Sets an error message for a field
  setErrors: (fields: Record<string, string>) => void; // Sets error messages for fields
  setFieldValue: (field: string, value: any) => void; // Sets a field value
  setValues: (fields: Record<string, any>) => void; // Sets multiple fields values
  validate: () => Promise<boolean>; // validates the form fields and returns the overall result
  handleSubmit: (cb: (values: Record<string, any>, ctx: SubmissionContext)) => () => void; // Creates a submission handler that calls the cb only after successful validation with the form values
  submitForm: (e: Event) => void; // Forces submission of a form after successful validation (calls
  handleReset: () => void; // Resets all fields' errors and meta and their values
  resetForm: (state?: Partial<FormState>) => void; // Resets all fields' errors and meta and their values to their initial state or the specified state


validationSchema?: Record<string, string | Function> | YupObjectSchema

Enables form-level validation, uses the specified schema to validate the fields. The schema can be either valid vee-validate global validators or functions or a yup object schema.

initialValues?: Record<string, any>

The initial values for the form, can be a reactive object or reference.

const { ... } = useForm({
  initialErrors: {
    email: '',
    password: 'p@$$w0rd',

initialErrors?: Record<string, string>

The initial errors for the fields, useful for non hydrated SSR applications like Laravel, errors are applied on mounted.

const { ... } = useForm({
  initialErrors: {
    email: 'This email is invalid',
    password: 'Password too short',

initialDirty?: Record<string, any>

The initial dirty status for the form fields, applied on mounted.

const { ... } = useForm({
  initialDirty: {
    email: true, // dirty
    password: false, // non-dirty

initialTouched?: Record<string, any>

The initial touched status for the form fields, applied on mounted.

const { ... } = useForm({
  initialTouched: {
    email: true, // touched
    password: false, // non-touched

validateOnMount?: boolean

If true, it will trigger validation for all fields once the form component is mounted.

Composable API

The following sections documents each available property on the useForm composable.

errors: Ref<Record<string, string>>

An object that maps field names to their error messages, it only takes the first error message of each field if multiple exists.

const { errors } = useForm();

errors.value; // access the errors value

Here is an example of its shape:

  email: "this field must be a valid email",
  password: "too short"

Any fields without error messages will not be included in the object. So you can safety iterate over it with Object.keys() knowing all the included fields are invalid.

isSubmitting: Ref<boolean>

Indicates if the submission handler is still running, once it resolves/rejects it will be automatically set to false again.

const { isSubmitting } = useForm();

isSubmitting.value; // true or false

meta: ComputedRef<FormMeta>

A computed property that contains an aggregated meta information/flags reflecting the state of all the fields inside the form.

interface FormMeta {
  touched: boolean; // if at least one field is touched (was blurred)
  dirty: boolean; // if at least one field is dirty (manipulated)
  valid: boolean; // if all fields are valid
  pending: boolean; // if at least one field is pending validation
  initialValues?: Record<string, any>; // a map of the form's initial values


const { meta } = useForm();

meta.value; // { valid: false, invalid: true, dirty: true, .... }

values: ComputedRef<Record<string, any>>

A computed property that contains the current form values

const { values } = useForm();

values.value; // { email: '', .... }

setFieldError: (field: string, message: string | undefined) => void

Sets a field's error message, useful for setting messages form an API or that are not available as a validation rule. Setting the message to undefined or an empty string clears the errors and marks the field as valid.

const { setFieldError } = useForm();

setFieldError('email', 'this email is already taken');

// Mark field as valid
setFieldError('email', undefined);

If you try to set an error for field doesn't exist, it will not affect the form's overall validity and will be ignored.

setErrors: (fields: Record<string, string | undefined>) => void

Sets multiple fields error messages, uses setFieldError internally.

const { setErrors } = useForm();

  email: 'this email is already taken',
  password: 'someone already has this password 🤪',
  firstName: undefined, // clears errors and marks the field as valid


Any missing fields you didn't pass to setErrors will be unaffected and their state will not change

setFieldValue: (field: string, value: any) => void

Sets a field's value, if a field does not exist it will not be reflected in the values ref. This will trigger validation on the field whose value changed.

const { setFieldValue } = useForm();

setFieldValue('email', '');

setValues: (fields: Record<string, any>) => void

Sets multiple fields values, will trigger validation for all the changed fields.

const { setValues } = useForm();

  email: '',
  password: 'p@a$$W0rD',

setFieldDirty: (field: string, isDirty: boolean) => void

Sets a field's dirty meta flag

const { setFieldDirty } = useForm();

setFieldDirty('email', true);

setDirty: (fields: Record<string, boolean>) => void

Sets multiple fields dirty meta flag, does not validate.

const { setDirty } = useForm();

  email: true,
  password: false,

setFieldTouched: (field: string, isTouched: boolean) => void

Sets a field's touched meta flag

const { setFieldTouched } = useForm();

setFieldTouched('email', true);

setTouched: (fields: Record<string, boolean>) => void

Sets multiple fields touched meta flag, does not validate.

const { setTouched } = useForm();

  email: true,
  password: false,

validate: () => Promise<boolean>

Validates all the fields and populates the errors object, returns a promise that resolves to a boolean indicating if the validation was successful or not

const { validate } = useForm();

await validate(); // true or false

handleSubmit: (cb: SubmissionHandler) => (evt?: Event) => Promise<void>

This is a higher order function used to create submit event handlers, You shouldn't use it as a handler for the events directly but rather use it to create those handlers.

The handlers created using this function will automatically prevent form submission and stop the propagation of the submit event.

It accepts a function which runs after validating the form and if all fields are valid. The callback you pass will receive the form values as the first argument, which is an object containing the fields' values.

  <form @submit="onSubmit"></form>

import { useForm } from 'vee-validate';

export default {
  setup() {
    const { handleSubmit } = useForm();

    // use `onSubmit` as an event handler for your forms
    const onSubmit = handleSubmit(values => {
      // pretty print the values object
      alert(JSON.stringify(values, null, 2));

    return {

For advanced forms, you may need to trigger various actions on the form in the submit handler. Your callback receives a FormActions object as part of the second argument along with the event object that triggered the submission if available.

const { handleSubmit } = useForm();

const onSubmit = handleSubmit((values, actions) => {
  actions.evt; // the event object that triggered the submission if available, might be undefined

  // the form object contains useful methods
  // set a single field value
  actions.setFieldValue('field', 'hello');
  // set multiple fields values
  actions.setValues({ email: 'value', password: 'hi' });
  // set a single field error
  actions.setFieldError('field', 'this field is bad');
  // set multiple fields errors
  actions.setErrors({ email: 'bad email', password: 'bad password' });

submitForm: (evt: Event) => void

Unlike handleSubmit this function can be used as an event handler for form submit event, it will prevent the propagation and submission of the forms using it as long as they are invalid. Once all the fields are valid it will submit the form with the native HTML behavior following the form element's action and method attributes.

This is useful if you plan to handle form submissions using a backend API like Laravel or whatever.

  <form @submit="submitForm" action="/api/login" method="post">
    <!-- ... -->

import { useForm } from 'vee-validate';

export default {
  setup() {
    const { submitForm } = useForm();

    return {

resetForm: (state?: Partial<FormState>) => void

Clears error messages, resets the meta state for all fields and reverts their values to their initial state. Accepts an optional object containing the new form state, useful if you need to reset the form values to different values other than their initial state.

This is the FormState interface:

type DirtyFlags = { [k: string]: boolean };
type TouchedFlags = { [k: string]: boolean };

interface FormState {
  // any error messages
  errors: Record<string, string>;
  // dirty meta flags
  dirty: DirtyFlags;
  // touched meta flags
  touched: TouchedFlags;
  // Form Values
  values: Record<string, any>;

In this example, the resetForm function is updating the fields current values to the ones provided, these values will be used as the new initial values for future resetForm or handleReset calls. This also applies if the Field component or useField used their individual resetField function.

const { resetForm } = useForm();

// ...
function onSubmit(values) {
  // send values to the API
  // ...

  // Reset the form values
    values: {
      firstName: '',
      lastName: '',
      email: '',
      password: '',

handleReset: () => void

Clears error messages, resets the meta state for all fields and reverts their values to their initial state. you can use this function as handler for the reset events on native form elements.

  <form @reset="handleReset">
    <!-- ... -->

import { useForm } from 'vee-validate';

export default {
  setup() {
    const { handleReset } = useForm();

    // you can use it in your code

    // or pass it to be used in the template
    return {