Form validation is an important part of any app.
In this article, we’ll look at how to use Vee-Validate 4 in our Vue 3 app for form validation.
Cross-Field Validation with defineRules
We can add cross-field validation without the Yup library.
To do this, we write:
<template>
<div>
<Form @submit="onSubmit">
<div>
<label for="password">Password</label>
<Field name="password" type="password" rules="required|min:5" />
<ErrorMessage name="password" />
</div>
<div>
<label for="passwordConfirmation">Confirm Password </label>
<Field
name="passwordConfirmation"
type="password"
rules="required|confirmed:@password"
/>
<ErrorMessage name="passwordConfirmation" />
</div>
<button type="submit">Submit</button>
</Form>
</div>
</template>
<script>
import { Field, Form, ErrorMessage, defineRule } from "vee-validate";
defineRule("required", (value) => {
if (!value) {
return "This is required";
}
return true;
});
defineRule("min", (value, [min]) => {
if (value && value.length < min) {
return `Should be at least ${min} characters`;
}
return true;
});
defineRule("confirmed", (value, [other]) => {
if (value !== other) {
return `Passwords do not match`;
}
return true;
});
export default {
name: "App",
components: {
Field,
Form,
ErrorMessage,
},
methods: {
onSubmit(values) {
alert(JSON.stringify(values, null, 2));
},
},
};
</script>
We called defineRule
to define the required
rule to check if the field is filled in.
min
checks if the field has a minimum amount of characters.
confirmed
checks that the other field’s value matches the current field’s value.
value
has the value of the field. And other
has the value of the other field.
Array Fields
We can validate fields that are rendered from an array.
To do this, we write:
<template>
<div>
<Form @submit="onSubmit" :validation-schema="schema">
<fieldset v-for="(user, idx) in users" :key="user.id">
<legend>User {{ idx }}</legend>
<label :for="`name_${idx}`">Name</label>
<Field :id="`name_${idx}`" :name="`users[${idx}].name`" />
<ErrorMessage :name="`users[${idx}].name`" as="p" />
<label :for="`email_${idx}`">Email</label>
<Field
:id="`email_${idx}`"
:name="`users[${idx}].email`"
type="email"
/>
<ErrorMessage :name="`users[${idx}].email`" as="p" />
<button type="button" @click="remove(user)">X</button>
</fieldset>
<button type="button" @click="add">Add User +</button>
<button type="submit">Submit</button>
</Form>
</div>
</template>
<script>
import { Field, Form, ErrorMessage } from "vee-validate";
import * as yup from "yup";
export default {
name: "App",
components: {
Field,
Form,
ErrorMessage,
},
data: () => {
const schema = yup.object().shape({
users: yup
.array()
.of(
yup.object().shape({
name: yup.string().required().label("Name"),
email: yup.string().email().required().label("Email"),
})
)
.strict(),
});
return {
schema,
users: [
{
id: Date.now(),
},
],
};
},
methods: {
onSubmit(values) {
alert(JSON.stringify(values, null, 2));
},
add() {
this.users.push({
id: Date.now(),
});
},
remove(item) {
const index = this.users.indexOf(item);
if (index === -1) {
return;
}
this.users.splice(index, 1);
},
},
};
</script>
We create the schema
object with Yup to call yup.array
to let us validate array.
Then we call of
to let us specify the validation schema for the objects inside.
The name
attributes of each field should be a string that takes the form of an array path.
Now when we type in something invalid in any entry, we’ll see errors displayed.
Conclusion
We can do cross-field validation and array field validations in our Vue 3 app with Vee-Validate 4.