JAVASCRIPT
Basic Form Validation with Vue 3 Composition API
Learn to implement flexible form validation logic in Vue 3 using the Composition API and a custom reusable composable for common validation rules.
// composables/useFormValidation.js
import { ref, computed } from 'vue';
export function useFormValidation(initialFormState, rules) {
const form = ref({ ...initialFormState });
const errors = ref({});
const validateField = (field, value) => {
errors.value[field] = [];
if (rules[field]) {
rules[field].forEach(rule => {
if (!rule.validator(value, form.value)) {
errors.value[field].push(rule.message);
}
});
}
};
const validateForm = () => {
let isValid = true;
for (const field in form.value) {
validateField(field, form.value[field]);
if (errors.value[field] && errors.value[field].length > 0) {
isValid = false;
}
}
return isValid;
};
const isFormValid = computed(() => {
for (const field in errors.value) {
if (errors.value[field] && errors.value[field].length > 0) {
return false;
}
}
return true;
});
const resetValidation = () => {
errors.value = {};
};
return {
form,
errors,
validateField,
validateForm,
isFormValid,
resetValidation,
};
}
// App.vue (Example Usage)
<template>
<form @submit.prevent="submitForm">
<div>
<label for="username">Username:</label>
<input type="text" id="username" v-model="form.username" @blur="validateField('username', form.username)" />
<p v-if="errors.username && errors.username.length" class="error">{{ errors.username[0] }}</p>
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" v-model="form.email" @blur="validateField('email', form.email)" />
<p v-if="errors.email && errors.email.length" class="error">{{ errors.email[0] }}</p>
</div>
<button type="submit" :disabled="!isFormValid && Object.keys(errors).length > 0">Submit</button>
</form>
<p v-if="submittedMessage">{{ submittedMessage }}</p>
</template>
<script setup>
import { ref, watch } from 'vue';
import { useFormValidation } from './composables/useFormValidation';
const initialForm = {
username: '',
email: '',
};
const validationRules = {
username: [
{ validator: value => value.length >= 3, message: 'Username must be at least 3 characters.' },
{ validator: value => /^[a-zA-Z0-9]+$/.test(value), message: 'Username can only contain letters and numbers.' },
],
email: [
{ validator: value => value.includes('@'), message: 'Invalid email address.' },
{ validator: value => value.length > 0, message: 'Email is required.' },
],
};
const { form, errors, validateField, validateForm, isFormValid, resetValidation } = useFormValidation(initialForm, validationRules);
const submittedMessage = ref('');
const submitForm = () => {
if (validateForm()) {
console.log('Form submitted successfully:', form.value);
submittedMessage.value = 'Form submitted successfully!';
form.value = { ...initialForm };
resetValidation();
setTimeout(() => submittedMessage.value = '', 3000);
} else {
console.log('Form has validation errors.');
submittedMessage.value = 'Please correct the errors.';
}
};
watch(form, () => {
}, { deep: true });
</script>
<style>
.error {
color: red;
font-size: 0.9em;
}
div {
margin-bottom: 10px;
}
label {
display: block;
margin-bottom: 5px;
}
input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 10px 15px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
</style>
How it works: This snippet provides a reusable `useFormValidation` composable for handling form input validation in Vue 3. It allows defining a schema of validation rules for each form field. The composable tracks form data, validation errors, and provides methods to validate individual fields, the entire form, and a computed property `isFormValid` to check the overall form status. The example demonstrates integrating this composable into a component, showing real-time error messages and disabling a submit button based on validation status.