Basics
These are the core concepts you need to know about vee-validate and its approach to form validation.
VeeValidate is a validation framework built specifically for Vue.js and as such it makes some assumptions and enforces "best-practices" for your forms while being versatile and customizable.
VeeValidate is a collection of function-based APIs and Vue components, the main things that will be covered is how to add rules and use them on your fields and error messages.
Validation Provider
First you need to register the ValidationProvider
component which acts as a validator for your fields, it works via scoped-slots to provide validation errors to your template.
Registering the Validation Provider
To register the ValidationProvider
component you can do that either locally within components (recommended):
import { ValidationProvider } from 'vee-validate';
export default {
components: {
ValidationProvider
}
};
Or globally using Vue.component
:
import { ValidationProvider } from 'vee-validate';
Vue.component('ValidationProvider', ValidationProvider);
// ...
If you are not using a bundler and using vee-validate in the browser or from a CDN:
<script>
// ...
Vue.component('validation-provider', VeeValidate.ValidationProvider);
// ...
</script>
After that you can use it in your components templates, typically you wrap your inputs with the ValidationProvider
:
<ValidationProvider v-slot="v">
<input v-model="value" type="text">
</ValidationProvider>
For the input
field or the component acting as an input, it should have a v-model
attached to it. This is because the ValidationProvider
searches its own children for inputs, so the v-model
acts as a hint for the ValidationProvider
.
However, if you cannot use v-model
on the input, you can use computed setters for cases like Vuex state and other complex input types where more than one state items are involved. For more information on using computed setters you can check the advanced guide.
If you cannot use either you can add a value
prop on your input and it should serve as a hint for vee-validate as well.
<ValidationProvider v-slot="v">
<input :value="value" @change="onInputChanged" type="text">
</ValidationProvider>
WARNING
If you cannot use neither v-model
or a value
binding on your inputs, you can still validate your fields. For example a file
type input usually doesn't use v-model
. To validate such fields, visit the model-less validation guide.
If you are using a CDN with vee-validate you may have to use the kebab
case as HTML is case insensitive, so you need to reference the ValidationProvider
as validation-provider
.
<validation-provider v-slot="v">
<input v-model="value" type="text">
</validation-provider>
Now that you have the field rendering correctly, you can display the field errors, You can use any HTML for that matter, like a simple span
tag:
<ValidationProvider v-slot="v">
<input v-model="value" type="text">
<span>{{ v.errors[0] }}</span>
</ValidationProvider>
The v
identifier is called slot props which lets components like the ValidationProvider
to send information to the slot, you can use ES6's object destructing to make things a little less verbose:
<ValidationProvider v-slot="{ errors }">
<input v-model="value" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
So far you only rendered the slot without any validation of any kind, the next section will walk you through adding validation rules and executing them.
Adding Rules
VeeValidate doesn't come installed with any validation rule by default, this is to keep the bundle size lean and as small as possible. The first of the function APIs is the extend
function.
Adding new rules with extend
is straight forward, in its simplest form it looks like this:
import { extend } from 'vee-validate';
extend('positive', value => {
return value >= 0;
});
That last snippet can be placed any where in our app, typically you should define your rules before you use them in your template, so your entry file or a dedicated validation.js
file is a great place to start.
The extend
function accepts the name of the rule and the validator function to use for that rule.
You can use the newly defined positive
rule like this:
<ValidationProvider rules="positive" v-slot="{ errors }">
<input v-model="value" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
You can add more rules to your field. To do that, define a rule that ensures that the field value must be an odd number:
import { extend } from 'vee-validate';
extend('odd', value => {
return value % 2 !== 0;
});
To make sure our field is validated by both rules, you append the odd
rule to the field to make sure it's positive and also an odd number:
<ValidationProvider rules="positive|odd" v-slot="{ errors }">
<input v-model="value" type="number">
<span>{{ errors[0] }}</span>
</ValidationProvider>
Notice that the |
pipe character separates the rules, this is inspired by Laravel's validation syntax, You can add as many rules as you want on your input:
<ValidationProvider rules="positive|odd|prime|fib" v-slot="{ errors }">
<input v-model="value" type="number">
<span>{{ errors[0] }}</span>
</ValidationProvider>
The string you sent to the rules
prop is called a string expression.
TIP
There is another advanced expression that you can express your rules with. See Rules Object Expression.
The last snippet used a function as the validation rule, there is a more extended form of rules that uses objects to include more metadata. The last snippet can also be re-written as:
import { extend } from 'vee-validate';
extend('odd', {
validate: value => {
return value % 2 !== 0;
}
});
Rule Arguments
Assuming you want to create a rule that checks the minimum the number of characters, it is clear that such a rule requires some sort of configuration. Ideally you should be able to re-use such a rule. For example you need to make sure the minimum number of characters is 3:
import { extend } from 'vee-validate';
extend('min', value => {
return value.length >= 3;
});
While this may serve your purpose, it is not useful for other fields. What if you want to check if the minimum is 4
instead?
Rules can receive arguments that each field can specify. To do that you use the extended form of validation rules and define the params
property that contains the argument names, this is what a min
rule with a configurable argument called length
:
import { extend } from 'vee-validate';
extend('min', {
validate(value, args) {
return value.length >= args.length;
},
params: ['length']
});
Note that the second parameter args
sent to the validate
method is an object containing keys that were specified in the params
array.
To configure the rule, use a Laravel-like syntax by appending a colon :
after the rule. This is an example of two fields using the same rule but with different length
for each of them:
<ValidationProvider rules="min:3" v-slot="{ errors }">
<input v-model="value" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
<ValidationProvider rules="min:6" v-slot="{ errors }">
<input v-model="value" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
Multiple Arguments
Rules arguments are one of the most versatile aspects of vee-validate, try something slightly complex. Create a rule and call it minmax
that will make sure the field value length is between a min
and a max
.
This rule will require two parameters, the first called min
and the second called max
. Start by defining the rule with extend
:
import { extend } from 'vee-validate';
extend('minmax', {
validate(value, args) {
const length = value.length;
return length >= args.min && length <= args.max;
},
params: ['min', 'max']
});
You can make things less verbose by destructuring the args object:
extend('minmax', {
validate(value, { min, max }) {
return value.length >= min && value.length <= max;
},
params: ['min', 'max']
});
To use this rule, you pass the minmax
rule to the rules
prop of the ValidationProvider
and you supply the arguments as a comma separated list:
<ValidationProvider rules="minmax:3,8" v-slot="{ errors }">
<input v-model="value" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
Now the field will be valid when the value is a string having a length between 3 and 8.
TIP
Arguments must follow the same order they were defined in as in the params
array.
Infinite Arguments
Some rules accept an infinite number of arguments, consider a one_of
rule that checks if the specified value in within a defined set, it looks like this:
import { extend } from 'vee-validate';
extend('one_of', (value, values) => {
return values.indexOf(value) !== -1;
});
For such rules you are not required to define a params
key, as vee-validate will automatically pass whatever specified in the ValidationProvider
rules prop to your rule, and it will maintain the same order.
<ValidationProvider rules="one_of:1,2,3,4,5,6,7,8,9" v-slot="{ errors }">
<input v-model="value" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
vee-validate will then pass an array containing: [1, 2, 3, 4, 5, 6, 7, 8, 9]
to your rule.
Messages
VeeValidate generates error messages for your fields, the last examples had This field is invalid
message which is the default message configured for all rules.
You can change that by returning strings in the validation function itself:
import { extend } from 'vee-validate';
extend('positive', value => {
if (value >= 0) {
return true;
}
return 'This field must be a positive number';
});
extend('odd', value => {
if (value % 2 !== 0) {
return true;
}
return 'This field must be an odd number';
});
You can also leave out messages from the validator
function and instead use the extended format to pass a dedicated message
property:
extend('odd', {
validate: value => {
return value % 2 !== 0;
},
message: 'This field must be an odd number'
});
This allows your validator
functions to be much clearer.
Field Name Placeholder
Sometimes you want your messages to have the following format:
The {fieldName} must be a valid...
The validator function doesn't accept the field name anywhere, but vee-validate offers simple interpolation mechanism for returned messages, you can use the {_field_}
placeholder in your string and it will be replaced with your field name automatically:
extend('positive', value => {
if (value >= 0) {
return true;
}
return 'The {_field_} field must be a positive number';
});
To display the field name, you set the name
prop on the validation provider:
<ValidationProvider name="age" rules="positive" v-slot="{ errors }">
<input v-model="value" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
Additionally, the field name can be automatically picked up from name
or id
attributes on HTML5 nodes if not specified already in the ValidationProvider
's name
prop.
Here since a name
prop is not set, vee-validate uses the name
attribute on the input tag as a field name.
<ValidationProvider rules="positive" v-slot="{ errors }">
<input v-model="value" name="age" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
Here since a name
prop is not set nor a name
attribute on the input, vee-validate uses the id
attribute on the input tag as a field name.
<ValidationProvider rules="positive" v-slot="{ errors }">
<input v-model="value" id="age" type="text">
<span>{{ errors[0] }}</span>
</ValidationProvider>
Arguments Placeholders
You can't really have the min
rule message to be "this field is invalid", this is not only confusing to the user, they will have no knowledge on how to fix them.
Client-side validation is all about UX, so vee-validate interpolation can parse placeholders that match the rule parameters, so to define such a message for the min
rule you can use a {length}
placeholder in the error message like this:
extend('min', {
validate(value, { length }) {
return value.length >= length;
},
params: ['length'],
message: 'The {_field_} field must have at least {length} characters'
});
One thing to note is that the parameter placeholder doesn't have underscores _
around it unlike the {_field_}
placeholder. This is a convention of vee-validate as there are special set of placeholders that have underscores around them. This is to prevent collisions and to make them distinct from rule parameters.
To solidify this concept, define a message for the minmax
rule:
extend('minmax', {
validate(value, { min, max }) {
return value.length >= min && value.length <= max;
},
params: ['min', 'max'],
message: 'The {_field_} field must have at least {min} characters and {max} characters at most'
});
Messages as Functions
If using interpolated strings is not flexible enough for you, using functions is also allowed. When using a function as your message, it has to return a string
. Function messages receive the field name and an object containing the placeholders mentioned earlier.
This is the previous example but with a function as our message:
extend('minmax', {
validate(value, { min, max }) {
return value.length >= min && value.length <= max;
},
params: ['min', 'max'],
message: (fieldName, placeholders) => {
return `The ${fieldName} field must have at least ${placeholders.min} characters and ${placeholders.max} characters at most`;
}
});
This allows you to manually interpolate or generate messages depending on your needs, this will come in handy when implementing localization using popular plugins like vue-i18n
. See The Localization Guide.
For reference these are the contents of the placeholders
object:
Prop | Description |
---|---|
_field_ | The field name. |
_value_ | The field value that was validated. |
_rule_ | The rule name that triggered this message. |
Along side any parameters configured in the params
array.
Multiple Messages
VeeValidate by default follows a fast-exit or bails whenever a rule fails and stops the validation pipeline for other rules, this is done to maximize performance and provide feedback to your users as fast as possible.
You could then be wondering why errors
is an array when vee-validate only generates one message at a time per field, this is because you can configure vee-validate to run all the validation rules specified for the field.
You could configure the ValidationProvider
component to run all the rules by setting the bails
prop to false
:
<ValidationProvider rules="positive|odd|prime|fib" :bails="false" v-slot="{ errors }">
<input v-model="value" type="text">
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</ValidationProvider>
Because errors
slot prop is a native JavaScript array, you can use v-for
directly to display the error messages generated for that field.
It can be annoying to define rules and messages for your application time and time again, vee-validate implemented the most common rules you will use in your application and they can be imported and used directly, In the next section you will learn about the validation rules that come bundled with vee-validate and how to use them.