Zod Schema Validation

If you prefer to use zod for schema validation instead of yup, you can do so with the @vee-validate/zod package.

With @vee-validate/zod you can use Zod typed schemas as drop-in replacements for yup schemas.

Install

To use this plugin, make sure to install these packages vee-validate, zod, and @vee-validate/zod.

shyarn add vee-validate zod @vee-validate/zod

# or with NPM
npm install vee-validate zod @vee-validate/zod

# or with Pnpm
pnpm add vee-validate zod @vee-validate/zod

Validating with Zod

You can create validation schemas for either field-level validation or form-level validation, the @vee-validate/zod exposes a toTypedSchema function that transform Zod’s schemas into something that can be understood by vee-validate main core and use them to perform validation. It also allows vee-validate to figure out the types for both the input values and the submitted values.

Field-level Validation

The toTypedSchema function accepts a Zod schema. You can use the converted schema by passing it to the rules prop present on the <Field /> component:

vue<template>
  <Form>
    <Field name="email" type="email" :rules="fieldSchema" />
    <ErrorMessage name="email" />
  </Form>
</template>

<script setup>
import { Field, Form, ErrorMessage } from 'vee-validate';
import { toTypedSchema } from '@vee-validate/zod';
import * as zod from 'zod';

const fieldSchema = toTypedSchema(zod.string().nonempty('Field is required').email('Must be a valid email'));
</script>

If you prefer to use the Composition API, then you can pass the converted schema to the useField function:

vue<template>
  <input name="email" v-model="value" type="email" />
  <span>{{ errorMessage }}</span>
</template>

<script setup>
import { useField } from 'vee-validate';
import { toTypedSchema } from '@vee-validate/zod';
import * as zod from 'zod';

const fieldSchema = toTypedSchema(
  zod.string().min(1, { message: 'Field is required' }).email({ message: 'Must be a valid email' })
);
const { value, errorMessage } = useField('email', fieldSchema);
</script>

Form-Level Validation

You can also use Zod’s zod.object to create validation schemas for your forms instead of individually passing it for each field, this is covered in general in the form-level validation section.

To be able to use zod.object to define form schemas, you will be using the same toTypedSchema function.

You can pass the converted schema to the validation-schema prop present on the <Form /> component:

vue<template>
  <Form :validation-schema="validationSchema" @submit="onSubmit">
    <Field name="email" type="email" />
    <ErrorMessage name="email" />

    <Field name="password" type="password" />
    <ErrorMessage name="password" />

    <button>Submit</button>
  </Form>
</template>

<script setup>
import { Form, Field, ErrorMessage } from 'vee-validate';
import { toTypedSchema } from '@vee-validate/zod';
import * as zod from 'zod';

const validationSchema = toTypedSchema(
  zod.object({
    email: zod.string().min(1, { message: 'This is required' }).email({ message: 'Must be a valid email' }),
    password: zod.string().min(1, { message: 'This is required' }).min(8, { message: 'Too short' }),
  })
);

function onSubmit(values) {
  alert(JSON.stringify(values, null, 2));
}
</script>

Alternatively, if you prefer to use the composition API, you can pass the converted schema as the validationSchema option accepted by the useForm function:

vue<template>
  <form @submit="onSubmit">
    <input name="email" v-model="email" type="email" />
    <span>{{ errors.email }}</span>

    <input name="password" v-model="password" type="password" />
    <span>{{ errors.password }}</span>

    <button>Submit</button>
  </form>
</template>

<script setup>
import { useField, useForm } from 'vee-validate';
import { toTypedSchema } from '@vee-validate/zod';
import * as zod from 'zod';

const validationSchema = toTypedSchema(
  zod.object({
    email: zod.string().min(1, { message: 'This is required' }).email({ message: 'Must be a valid email' }),
    password: zod.string().min(1, { message: 'This is required' }).min(8, { message: 'Too short' }),
  })
);

const { handleSubmit, errors } = useForm({
  validationSchema,
});

const { value: email } = useField('email');
const { value: password } = useField('password');

const onSubmit = handleSubmit(values => {
  alert(JSON.stringify(values, null, 2));
});
</script>

TypeScript Form Values Inference

You can find more information on how typed schemas work in vee-validate here

refine/superRefine

There is a known issue with Zod’s refine and superRefine not executing whenever some object keys are missing which is common with forms. This is not an issue with vee-validate as it is a design choice in Zod at the moment. Refer to this issue for explanations and further reading.