Vue form Validation using VeeValidate in Vue.js

Guide of Vue form Validation – As technology advances, we face new challenges in developing cutting-edge solutions. Validating your forms in the browser is essential. This can save application resources while also improving the user experience.

Vue has its built-in validation but recommends libraries such as Vee Validate, tested to work on all browsers.

In this tutorial, we will discuss and set up form validation using the vee-validate library.

Prerequisites of Vue form Validation

It is important to have the following things to follow along with this article:

  • Node installed
  • Vue installed
  • yarn
  • Basic knowledge of JavaScript programming.
  • Basic knowledge and practice of Vue.
  • Text editor installed. Preferably VS Code

Why Client-Side Validation

Client-side validation is critical because it gives consumers rapid feedback, which improves the user experience. As a result, application resources are save by removing the response request cycle process, resulting in bandwidth and time savings.

This isn’t to suggest that server-side validation shouldn’t be use on an application; client-side validation can be turn off in the browser, but it’s best to validate both the client and the server.

Project SetUp for Vue form Validation

Make sure Vue is installed and set up on your computer. Using the command below, create a new Vue app:

vue create vue-form-validation

We’ll begin by installing Tailwind and creating a sample template to practice with. Download and install the Tailwind plugin.

Install the plugin using the command below in the newly established repository:

vue add tailwind

Let’s start by making a new component and configuring the tailwind template. Copy the body components from the below template.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://unpkg.com/[email protected]^2/dist/tailwind.min.css" rel="stylesheet">
  <title>Document</title>
</head>
<body>
  <div class="grid justify-items-center shadow-md flex-shrink md:flex-shrink-0">
    <div class="w-3/5 bg-white">
      <div class="p-8">
        <!--alert message-->
        <div
          class="shadow-lg mt-3 pt-3 pb-3 w-full text-white text-center
            hover:bg-indigo-400 rounded-full cursor-pointer hidden"
        >
        </div>
        
        <form>
          <!-- Username -->
          <div>
            <label for="username" class="text-xs text-gray-500">Username</label>
            <input
              id="username"
              class="bg-transparent border-b m-auto block border-gray-500 w-full mb-6
           text-gray-700 pb-1"
              type="text"
              placeholder=""
            />
          </div>
          <!-- Email -->
          <div>
            <label id="email" class="text-xs text-gray-500">Email</label>
            <input
              id="email"
              class="bg-transparent border-b m-auto block border-gray-500
            w-full mb-6 text-grey-700 pb-1"
              type="email"
              placeholder=""
            />
          </div>
          <!-- Age -->
          <div>
            <label id="age" class="text-xs text-gray-500">Age</label>
            <input
              id="age"
              name="age"
              class="bg-transparent border-b m-auto block border-gray-500
            w-full mb-6 text-grey-700 pb-1"
              type="number"
              placeholder=""
            />
          </div>
          <!-- Password -->
          <div>
            <label id="password" class="text-xs text-gray-500">Password</label>
            <input
              id="password"
              name="password"
              class="bg-transparent border-b m-auto block border-gray-500
            w-full mb-6 text-grey-700 pb-1"
              type="password"
              placeholder=""
            />
          </div>
          <!-- Password Confirmation -->
          <div>
            <label id="password_confirmation" class="text-xs text-gray-500"
              >Password Confirmation</label
            >
            <input
              id="password_confirmation"
              name="password_confirmation"
              class="bg-transparent border-b m-auto block border-gray-500
            w-full mb-6 text-grey-700 pb-1"
              type="password"
              placeholder=""
            />
          </div>
          <!-- Country -->
          <div>
            <label id="country" class="text-xs text-gray-500">Country</label>
            <select
              class="bg-transparent w-full py-1.5 px-3 text-gray-800 border-b border-gray-500
            transition duration-500 focus:outline-none focus:border-black rounded"
            >
            <option value="Pak">Pakistan</option>
              <option value="USA">USA</option>
              <option value="Mexico">Mexico</option>
              <option value="Germany">Germany</option>
              <option value="Africa">Africa</option>
            </select>
          </div>
          <input
            class="shadow-lg mt-3 pt-3 pb-3 w-full text-white bg-indigo-500
            hover:bg-indigo-400 rounded-full cursor-pointer "
            type="submit"
            value="Create account"
          />
        </form>
        <div class="text-center mt-4">
          <p class="text-sm text-gray-600">
            Already have an account?
            <a href="#" class="no-underline text-indigo-500 font-bold hover:text-indigo-400"
              >Sign in</a
            >
          </p>
        </div>
      </div>
    </div>
  </div>
</body>
</html>

Output:

img

Once you’ve start the server and navigate to the local port, you’ll be present with a signup form. Feel free to change it up as you see fit.

Introducing VeeValidate

VeeValidate is a powerful validation tool. Let’s take a look around the library before we start working with it.

Components and the composition API are two methods of form validation provided by the above library. In this tutorial, we’ll use a component-based approach.

We are provided with the following components:

  • Form component renders a form and wraps all form elements.
  • Field component represents form inputs and renders any HTML element.
  • ErrorMessage component displays an error message for a field.

Let’s define the validation process and see how it relates to the mentioned components:

  1. Wrap your form with the Form component, overwriting the default form elements.
  2. Replace input element with Field component and add an identifier name to the component.
  3. Add validation rules.
  4. Handle validation errors.

Let’s dig in and examine how validation works now that you have a fundamental understanding of the library.

Install the Vee Validate library:

yarn add [email protected]

To set up the validator, create an empty folder plugin in the src folder after installation.

In the folder created, add a new file validation.js:

Configure the plugin,

import { Form as VeeForm, Field as VeeField } from "vee-validate";

export default {
  install(app) {
    app.component("VeeForm", VeeForm);
    app.component("VeeField", VeeField);
  },
};

The components from the vee-validate library are import and registered, using aliases to avoid conflict with HTML elements.

We need to tell Vue that we’re using the vee-validate package, so change the main.js file to match this:

import { createApp } from "vue";
import VeeValidatePlugin from "./plugin/validation";
import App from "./App.vue";
import "./assets/tailwind.css";

const app = createApp(App);

app.use(VeeValidatePlugin);

app.mount("#app");

Replace the form element in our template with the vee-form component.

If there are no problem messages in our console after refreshing the browser, vee-validate has been successfully install.

Vue Form Validation

Step 01: Username validation

Our first input field, username, will be validate.

We should rename our input element to vee-field component and provide our Field components a name identifier. The identifier aids in the identification of the component and error messages.

Our element should match:

<vee-field
  name="username"
  id="username"
  class="bg-transparent border-b m-auto block border-gray-500 w-full mb-6text-gray-700 pb-1"
  type="text"
  placeholder=""
/>

Let’s add our rules now that we’ve completed the first step of form validation.

Step 02: Register Rules Globally

To prevent code duplication, we’ll register the rules globally, but first import the vee-validate-rule library.

yarn add @vee-validate/rules

Rules are a function that takes an input process and returns an error message, and they give a list of criteria that a value must fulfill. In our validation.js file, we set up the library as follows:

import {
  Form as VeeForm,
  Field as VeeField,
  defineRule,
  ErrorMessage,
} from "vee-validate";

import { required } from "@vee-validate/rules";

export default {
  install(app) {
    app.component("VeeForm", VeeForm);
    app.component("VeeField", VeeField);
    app.component("ErrorMessage", ErrorMessage);

    defineRule("required", required);
  },
};

We import the defineRule and ErrorMessage from vee-validate to prevent moving back and forth in files. This is use to specify rules and set error messages correspondingly.

The ErrorMessage component is registered, and a required rule is defined, which ensures that an input element is present.

The global validator provides the defineRule function. It takes two arguments: an identifier (which is the name of the rule) and a validator function to check the field value.

Step 03: Creating ground rules

Let’s return to creating our ground rules. We’ll use the schema property of the vee-validate property. We will be able to delegate our rules to an external object as a result of this.

Create a schema object in the component where the tailwind template was pasted:

<script>
export default {
  name: 'ComponentName', // replace with component-name
  data() {
    return {
      schema: {
        username: 'required'
      }
    }
  }
}
</script>

We can now bind our object to the form component

<vee-form :validation-schema="schema">

Step 3 has been completed. The error component will be put up next.

Define the ErrorMessage component underneath the field component with some basic style and the name identifier as follows:

<ErrorMessage class="text-red-600" name="username" />

It’s worth noting that the component’s name must match that of the schema object and field component.

Let’s create a guard that only allows validation when the form is submit. Add a vee-validate submit an event, then change the Form component to match:

<vee-form :validation-schema="schema" @submit="register" >

We have emitted a register function in our Form component. Let’s define it:

methods: {
  register(values){
    console.log(values);
  },
};

The vee-validate library provides the values parameter, which saves all of the values from the form inputs. The values will be log in the console when validation returns a truth.

Submit the form after filling out the username field. The value of the form should be return to the console. If you try to leave it blank, you’ll get a validation error.

Step 04: validation of some additional input components

Let’s validate some additional input components now that we’ve learned about validation and vee-validate.

Import and save rules that will be applies to our forms. Validation.js should be updated to match the file:

import {
  Form as VeeForm,
  Field as VeeField,
  defineRule,
  ErrorMessage,
} from "vee-validate";
import {
  required,
  min,
  max,
  alpha_spaces as alphaSpaces,
  email,
  min_value as minVal,
  max_value as maxVal,
  not_one_of as excluded,
  confirmed,
} from "@vee-validate/rules";

export default {
  install(app) {
    app.component("VeeForm", VeeForm);
    app.component("VeeField", VeeField);
    app.component("ErrorMessage", ErrorMessage);

    defineRule("required", required);
    defineRule("min", min);
    defineRule("max", max);
    defineRule("alpha_spaces", alphaSpaces);
    defineRule("email", email);
    defineRule("min_value", minVal);
    defineRule("max_value", maxVal);
    defineRule("excluded", excluded);
    defineRule("country_excluded", excluded);
    defineRule("password_mismatch", confirmed);
  },
};

Some of our rules, such as apha_spaces and not_one_of, have aliases. To avoid linting and increase readability, do this.

Open the template file and change the input fields and schema object now that we have our rules in place. Multiple rules will be separate by a pipe character when updating the schema object.

schema: {
  username: 'required|min:3|max:50|alpha_spaces',
  email: 'required|min:3|max:20|email',
  age: 'required|min_value:1|max_value:100',
  password: 'required',
  password_confirmation: 'password_mismatch:@password',
  country: 'required|country_excluded:Africa',
}

As shown in the username example above, we may edit our input items and ErrorMessage. Validation of our form should now be complete.

The drop-down field will cause you problems while updating the input components. This will allow us to investigate a different field property, the as property.

It comes with an input element by default, but it also allows us to render a root node. The Country field is update to match:

<div>
  <label id="country" class="text-xs text-gray-500">
    Country
  </label>
  <vee-field
    as="select"
    name="country"
    class="bg-transparent w-full py-1.5 px-3 text-gray-800 border-b border-gray-500
    transition duration-500 focus:outline-none focus:border-black rounded"
  >
    <option value="Pak">Pakistan</option>
    <option value="USA">USA</option>
    <option value="Mexico">Mexico</option>
    <option value="Germany">Germany</option>
    <option value="Africa">Africa</option>
  </vee-field>
  <ErrorMessage class="text-red-600" name="country" />
</div>

The element in the source will have a select element property when you inspect it. The as an attribute has been use to alter the default input element.

Let’s see what we can accomplish with the library while we’re still on the Country field. Create a default choice for the field by selecting it from the drop-down menu.

The initialValues property is use to accomplish this. It transmits objects with field names as keys and their values as values.

After our schema object, create a userData object.

userData: {
  country: 'Pak',
},

Update the vee-form component to match the above:

<vee-form :validation-schema="schema" @submit="register" :initial-values="userData" >

It’s worth noting that we’re tying the initial value to the userData object, which has key-value attributes. The object value will be used as the drop-default down’s select element.

Custom Error Messages

Vee-validate comes with a set of default error messages, but we may change them to fit our own. The configure function will assist us in accomplishing this goal.

Install the following function:

import {
  Form as VeeForm,
  Field as VeeField,
  defineRule,
  ErrorMessage,
  configure,
} from "vee-validate";

Let’s now create our custom rules, after the last rule registered with the defineRule, add the configure function.

configure({
  generateMessage: (context) => {
    const messages = {
      required: `This field ${context.field} is required.`,
      min: `This field ${context.field} is too short.`,
      max: `This field ${context.field} is too long.`,
      alpha_spaces: `This field ${context.field} can only contain letters and spaces.`,
      email: `This field ${context.field} is not a valid email.`,
      min_value: `This field ${context.field} is too low.`,
      max_value: `This field ${context.field} is too high.`,
      excluded: "This field is not allowed.",
      country_excluded: "We do not allow users from this location",
      password_mismatch: `This field ${context.field} does not match.`,
    };
    const message = messages[context.rule.name]
      ? messages[context.rule.name]
      : `The field ${context.field} is invalid`;
    return message;
  },
});

The configure functions take an argument context and store a message that overrides the error messages that are generated by default. The input names are saved in the context argument.

We have the ternary operator which returns customized error messages.

Validation Triggers

Validation occurs when specific triggers are triggered.

In the configure method, register it after the generateMessage object. The configure function also provides this.

  • ValidateOnBlur happens after a blur event on the input element.
  • ValidationOnChange happens after the change event.
  • ValidationOnInput happens when a field value is changed.
  • ValidationOnModelUpdate happens after form submission.

In the configure function, after the generateMessage object, add the code below:

validateOnBlur: true,
validateOnChange: true,
validateOnInput: false,
validateOnModelUpdate: true,

This is simply my taste; you are free to customize the validation triggers by specifying your own unique boolean inputs.

Add an Alert Message

Disabling users from submitting spam forms is a great practice. A user should not submit the same form more than once.

Update our data using the attributes listed above in our component. After the userData object, add the attributes.

reg_in_submission: false,
reg_show_alert: false,
reg_alert_variant: 'bg-indigo-500',
reg_alert_message: 'Please wait! Account is being registered.',

These are the attributes we use to prevent the alert element from appearing while the form is being validated. Apply the defined attributes to the alert element.

<div class="shadow-lg mt-3 pt-3 pb-3 w-full text-white text-center
  hover:bg-indigo-400 rounded-full cursor-pointer"
  v-if="reg_show_alert"
  :class="reg_alert_variant"
>
  {{ reg_alert_msg }}
</div>

If set to a boolean, the v-if directive toggles the alert message, and v-bind displays our tailwind properties. In the register function, define the attributes and update it to match:

register(values) {
  this.reg_show_alert = true;
  this.reg_in_submission = true;
  this.reg_alert_variant = 'bg-indigo-500';
  this.reg_alert_msg = 'Please wait! Your account is being created.';

  this.reg_alert_variant = 'bg-blue-500';
  this.reg_alert_msg = 'Success! Your account has been created.';

  console.log(values);
},

We have defined alert properties and messages but have not included them in our form. Update our button element to match:

<button
  :disabled="reg_in_submission"
  class="shadow-lg mt-3 pt-3 pb-3 w-full text-white bg-indigo-500
  hover:bg-indigo-400 rounded-full cursor-pointer "
  type="submit"
  value="Create account"
  >
  Create Account
</button>

To prevent multiple form submissions, the form will be deactivated after submission and a warning message will be displayed. Form input values will be recorded as an object in the console as well.

Conclusion of Vue form Validation

We learned about form validation in vue and how to use the vee-validate library to do it. That’s all for this article if you have any confusion contact us through our website or email us at [email protected] or by using LinkedIn.

Leave a Comment