Vuelidate is an adaptable and user-friendly form validation solution designed for Vue.js. In this tutorial, I will walk you through the process of installing and configuring Vuelidate within a Vite + Vue project.
Step 1: Setting Up a Vite + Vue Project
To begin, let's initiate a new project using Vite. We'll utilize "create-vite," a tool that enables rapid generation of project templates for popular frameworks:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devOnce the project is generated, navigate to its directory:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devStep 2: Installing Vuelidate
Vuelidate 2.x is compatible with Vue 3. To install Vuelidate, we need to include the following dependencies:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devStep 3: Configuring Vuelidate for Form Validation
In earlier versions of Vuelidate (0.x), we could apply it globally across our application using the Vuelidate plugin. However, this approach has been removed in the latest versions. The current approach involves using the useValidate function within the component we intend to validate.
Let's proceed by creating a basic registration form with fields for name, email, password, and password confirmation. We'll place this form in a new component named ‘RegisterForm.vue’ within the components folder.
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devThe fields are validated based on the rules defined in the "rules" object. If any field fails the validations, an error message is displayed associated with the corresponding field. When the form is submitted, the "handleSubmit" function validates the fields using Vuelidate and shows an alert with the result of the form submission.
Code Breakdown
Importing Modules:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devThe previous code snippet begins by importing essential functionalities from both Vue and Vuelidate. It employs the reactive and computed elements to enable dynamic updates and efficient computations. The code further utilizes the useVuelidate function from the Vuelidate library. Additionally importing some validators that we will use later in our validation rules.
Reactive Form Object:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devCreating a form object using Vue's reactive function, serving as a container for the values of form fields. This object is initially populated with empty strings, and as users engage with the form on the user interface and input data, the content of these fields within the object dynamically updates to reflect the entered values.
Validation Rules:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devWe created a rules object which will serve as validation guidelines for each form field. These rules are wrapped within a function that keeps them responsive, allowing them to update when related fields change. In this order, specific requirements are defined like this: the name field must have a value, the email field should contain a valid email address, the password field must be at least 8 characters long, and the confirmPassword field needs to match the value entered in the password field.
Step 4: Testing the Form
Integrate the form into your main component (App.vue) for testing purposes:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run devNow, you can launch the Vite development server to test the form and its validations:
/* App.vue */
<template>
<RegisterForm />
</template>
<script>
import RegisterForm from './components/RegisterForm.vue'
</script>
/* RegisterForm.vue */
<template>
<!-- The form uses @submit.prevent to capture the form submission event and execute the "handleSubmit" function. -->
<form @submit.prevent="handleSubmit">
<div class="field-container">
<!-- Input field for name -->
<label for="name">Name:</label>
<input v-model="form.name" type="text" id="name" placeholder="Insert your name">
<!-- Display an error message if the name field doesn't pass the validations defined in "rules" -->
<span v-if="v$.name.$error">{{ v$.name.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for email -->
<label for="email">Email:</label>
<input v-model="form.email" type="text" id="email" placeholder="Insert your email">
<!-- Display an error message if the email field doesn't pass the validations defined in "rules" -->
<span v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for password -->
<label for="password">Password:</label>
<input v-model="form.password" type="password" id="password" placeholder="Insert your password">
<!-- Display an error message if the password field doesn't pass the validations defined in "rules" -->
<span v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
</div>
<div class="field-container">
<!-- Input field for confirming the password -->
<input v-model="form.confirmPassword" type="password" placeholder="Confirm password">
<!-- Display an error message if the password confirmation field doesn't pass the validations defined in "rules" -->
<span v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
</div>
<!-- Button to submit the form -->
<button type="submit">Sign in</button>
</form>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
// Create a reactive "form" object to store the values of the form fields
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
// Define validation rules for each form field using "computed"
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
// Use the "useVuelidate" function to perform form validation
const v$ = useVuelidate(rules, form)
// Function to handle form submission
async function handleSubmit() {
// Validate the form fields
const result = await v$.value.$validate()
if (!result) {
// If there are errors in the form, show an alert indicating that the form is invalid
alert('The form has errors')
return
}
// If the form is valid, perform some action with the form data
alert('Form submitted successfully')
}
</script>
<style lang="css">
form {
width: 400px;
margin: 0 auto;
background-color: #f1f1f1;
padding: 30px;
border-radius: 20px;
}
div.field-container {
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 118px;
}
label {
text-align: left;
}
input {
display: block;
box-sizing: border-box;
border: none;
outline: none;
border-bottom: 1px solid #ddd;
border-radius: 20px;
font-size: 1em;
padding: 20px;
margin: 10px 0 5px 0;
width: 100%;
}
span {
color: red;
font-size: 0.8em;
text-align: left;
}
button {
background-color: #3498db;
padding: 10px 20px;
margin-top: 10px;
border: none;
color: white;
}
</style>
/* changeDirectory.bash */
cd my-vue-app
/* computedRules.js */
const rules = computed(() => {
return {
name: { required }, // Name is required
email: {
required, // Email is required
email // Must be a valid email address
},
password: {
required, // Password is required
minLength: minLength(8) // Password must have at least 8 characters
},
confirmPassword: {
required, // Password confirmation is required
sameAs: sameAs(form.password) // Must match the value of the entered password
}
}
})
/* createVite.bash */
yarn create vite my-vue-app --template vue
/* imports.js */
import { reactive, computed } from 'vue'
import { useVuelidate } from '@vuelidate/core'
import { minLength, required, email, sameAs } from '@vuelidate/validators'
/* installVuelidate.bash */
yarn add @vuelidate/core @vuelidate/validators
/* reactiveForm.js */
const form = reactive({
name: '',
email: '',
password: '',
confirmPassword: ''
})
/* runProject.bash */
npm run dev
Empty Fields & Error Messages

Password Validation

Successful Validation

Step 5: Conclusion and next steps
With this setup, you can effectively assess form validation using Vuelidate within your Vite + Vue project. Remember that Vuelidate offers a variety of validators beyond those covered here. For a complete list of validators, refer to the official documentation. If you're up for a challenge, you can even create your own custom validators.
Happy coding!