Vue 3 + VeeValidate - Form Validation Example (Composition API)
Example built with Vue 3.2.31 and VeeValidate 4.5.11
Other versions available:
- Angular Reactive Forms: Angular 14, 10, 9, 8, 7, 6
- Angular Template-Driven Forms: Angular 14, 10, 9, 8, 7, 6
- Blazor: Blazor WebAssembly
- Next.js: Next.js
- React + Formik: Formik 2, 1
- React Hook Form: React Hook Form 7, 6
- Vue + VeeValidate: Vue 3 Options API, Vue 2
- Vue + Vuelidate: Vue 2
This is a quick example of how to setup form validation in Vue 3 using VeeValidate.
Vue Composition API
The component in the example is built with the new Vue Composition API that comes with Vue 3, component logic is located within a <script setup>
block that shares the same scope as the template, so variables and functions declared in the block are directly accessible to the template. For more info on the Vue Composition API see https://vuejs.org/guide/extras/composition-api-faq.html.
For the same example built with the traditional Vue Options API that comes with Vue 2 & 3 see Vue 3 + VeeValidate - Form Validation Example (Options API).
VeeValidate
VeeValidate is a library for building, validating and handling forms in Vue.js. VeeValidate 4 was recently released and is compatible with Vue 3, the official docs are available at https://vee-validate.logaretm.com/v4.
The example is a simple registration form with pretty standard fields for title, first name, last name, date of birth, email, password, confirm password and an accept terms and conditions checkbox. All fields are required including the checkbox, the dob must be a valid date, the email address must be in a valid format, the password field must have a min length of 6, and the confirm password and password fields must match.
Styling of the example is all done with Bootstrap 4.5 CSS, for more info see https://getbootstrap.com/docs/4.5/getting-started/introduction/.
Here it is in action: (See on StackBlitz at https://stackblitz.com/edit/vue-3-veevalidate-form-validation-example)
Vue 3 + VeeValidate Form Validation App Component with Composition API
The app component code defines the form validation rules with the Yup schema validation library which VeeValidate supports out of the box, for more info on Yup see https://github.com/jquense/yup.
The onSubmit()
method is called when the form is valid and submitted, and simply displays the contents of the form in a javascript alert.
The app component template contains the form with all of the input fields and validation messages. The form and fields are built with the VeeValidate <Form />
and <Field />
components which automatically hook into the validation rules (schema) based on the name of the field.
The form calls the onSubmit()
method when the form is submitted and valid. Validation rules are bound to the form with the validation-schema
prop, and validation errors are provided to the form template via the scoped slot v-slot="{ errors }"
.
<script setup>
import { Form, Field } from 'vee-validate';
import * as Yup from 'yup';
const schema = Yup.object().shape({
title: Yup.string()
.required('Title is required'),
firstName: Yup.string()
.required('First Name is required'),
lastName: Yup.string()
.required('Last name is required'),
dob: Yup.string()
.required('Date of Birth is required')
.matches(/^\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/, 'Date of Birth must be a valid date in the format YYYY-MM-DD'),
email: Yup.string()
.required('Email is required')
.email('Email is invalid'),
password: Yup.string()
.min(6, 'Password must be at least 6 characters')
.required('Password is required'),
confirmPassword: Yup.string()
.oneOf([Yup.ref('password'), null], 'Passwords must match')
.required('Confirm Password is required'),
acceptTerms: Yup.string()
.required('Accept Ts & Cs is required')
});
function onSubmit(values) {
// display form values on success
alert('SUCCESS!! :-)\n\n' + JSON.stringify(values, null, 4));
}
</script>
<template>
<div class="card m-3">
<h5 class="card-header">Vue 3 + VeeValidate - Form Validation Example</h5>
<div class="card-body">
<Form @submit="onSubmit" :validation-schema="schema" v-slot="{ errors }">
<div class="form-row">
<div class="form-group col">
<label>Title</label>
<Field name="title" as="select" class="form-control" :class="{ 'is-invalid': errors.title }">
<option value=""></option>
<option value="Mr">Mr</option>
<option value="Mrs">Mrs</option>
<option value="Miss">Miss</option>
<option value="Ms">Ms</option>
</Field>
<div class="invalid-feedback">{{errors.title}}</div>
</div>
<div class="form-group col-5">
<label>First Name</label>
<Field name="firstName" type="text" class="form-control" :class="{ 'is-invalid': errors.firstName }" />
<div class="invalid-feedback">{{errors.firstName}}</div>
</div>
<div class="form-group col-5">
<label>Last Name</label>
<Field name="lastName" type="text" class="form-control" :class="{ 'is-invalid': errors.lastName }" />
<div class="invalid-feedback">{{errors.lastName}}</div>
</div>
</div>
<div class="form-row">
<div class="form-group col">
<label>Date of Birth</label>
<Field name="dob" type="date" class="form-control" :class="{ 'is-invalid': errors.dob }" />
<div class="invalid-feedback">{{errors.dob}}</div>
</div>
<div class="form-group col">
<label>Email</label>
<Field name="email" type="text" class="form-control" :class="{ 'is-invalid': errors.email }" />
<div class="invalid-feedback">{{errors.email}}</div>
</div>
</div>
<div class="form-row">
<div class="form-group col">
<label>Password</label>
<Field name="password" type="password" class="form-control" :class="{ 'is-invalid': errors.password }" />
<div class="invalid-feedback">{{errors.password}}</div>
</div>
<div class="form-group col">
<label>Confirm Password</label>
<Field name="confirmPassword" type="password" class="form-control" :class="{ 'is-invalid': errors.confirmPassword }" />
<div class="invalid-feedback">{{errors.confirmPassword}}</div>
</div>
</div>
<div class="form-group form-check">
<Field name="acceptTerms" type="checkbox" id="acceptTerms" value="true" class="form-check-input" :class="{ 'is-invalid': errors.acceptTerms }" />
<label for="acceptTerms" class="form-check-label">Accept Terms & Conditions</label>
<div class="invalid-feedback">{{errors.acceptTerms}}</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary mr-1">Register</button>
<button type="reset" class="btn btn-secondary">Reset</button>
</div>
</Form>
</div>
</div>
</template>
Need Some Vue 3 Help?
Search fiverr for freelance Vue 3 developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!