Form validation using Vest Part 1
Learn more aboutVest
Create your account
0 / 50
// validation.ts
import { create, test, enforce, only } from "vest";
import { isEmail } from "validator";
enforce.extend({ isEmail });
export default create((data = {}, changedField) => {
only(changedField);
test("name", "What's your name?", () => {
enforce(data.name).isNotBlank()
})
test("email", "What is your email?", () => {
enforce(data.email).isNotBlank()
});
test("email", "Please enter a valid email address.", () => {
enforce(data.email).isEmail()
});
});
More ruleshere…
// twitterForm.vue
<script setup lang="ts">
import suite from '~/logic/validation'
import classNames from "vest/classNames";
const state = reactive({ name: '', email: '', res: suite.get() })
const { name, email, res } = toRefs(state)
const classes = computed(() => classNames(res.value, { invalid: "invalid" }))
const validateForm = (field: string) => res.value = suite({ name: name.value, email: email.value }, field)
</script>
<template>
<div class="px-10 py-8 dark:bg-dark-900 rounded-xl">
<div class="logo w-full flex justify-center items-center ">
<!-- twitter logo -->
</div>
<div class="w-full flex flex-col justify-center items-stretch space-y-8">
<h4 class="self-start font-bold text-2xl">Create your account</h4>
<div class="inputWrapperStyle" :class="classes('name')">
<input
id="name"
v-model="name"
type="text"
placeholder=" "
maxlength="50"
@input="validateForm('name')"
class="inputStyle"
/>
<label for="name" class="labelStyle">Name</label>
<span
class="absolute top-0 right-2 opacity-0 group-focus-within:opacity-100 text-gray-500"
>{{ name.length }} / 50</span>
<span class="absolute text-xs text-red-500">{{ [...res.getErrors('name')][0] }}</span>
</div>
<div class="inputWrapperStyle" :class="classes('email')">
<input
id="Email"
v-model="email"
type="text"
placeholder=" "
@input="validateForm('email')"
class="inputStyle"
/>
<label for="email" class="labelStyle">Email</label>
<span class="absolute text-xs text-red-500">{{ [...res.getErrors('email')][0] }}</span>
</div>
</div>
<button
:disabled="!res.isValid()"
class="mt-14 w-full rounded-full py-2 text-sm font-semibold text-white bg-light-blue-500"
>Next</button>
</div>
</template>
<style scoped>
.inputWrapperStyle {
@apply relative group border dark:border-dark-50 rounded dark:text-gray-500 focus-within:(border-light-blue-500 text-light-blue-500 dark:text-light-blue-500);
}
.inputStyle {
@apply px-2 pt-6 pb-2 rounded dark:text-white text-dark-200 leading-6 block w-full appearance-none focus:outline-none bg-transparent;
}
.labelStyle {
@apply font-thin absolute top-3 text-lg left-2 origin-top-left duration-250 ease-in-out;
}
input:focus-within ~ label,
input:not(:placeholder-shown) ~ label {
@apply transform scale-75 -translate-y-3;
}
label {
@apply pointer-events-none;
}
.word-length {
@apply text-xs absolute;
}
.dob {
@apply pl-2.5 pt-2.5;
}
select {
@apply px-2 pt-8 pb-2 border-1 rounded-md text-lg appearance-none;
}
.invalid {
@apply !border-red-600 dark:!border-red-500 rounded focus-within:(!border-light-red-500 !text-red-500 dark:!text-red-500);
}
button:disabled,
button[disabled] {
@apply !bg-gray-500 !text-dark-50;
}
Made with❤by leovoon