Forms have always been a pain to work with in any project. You have to handle the form state, validation, error messages, backend validation and more. Regle is a new Vue form validation library that greatly simplifies working with forms.
What is Regle?
Regle is a new data-driven Vue form validation library similar to Vuelidate. It's inspired by Vuelidate, and if you’ve used that before, Regle will feel very familiar. Since Vuelidate isn't actively maintained anymore, Regle is kind of like its successor. It keeps what worked well in Vuelidate, fixes some issues, and adds cool new features.
Key features of Regle:
- Data-driven validation Instead of being tied to components or the DOM, Regle is completely data-driven. This gives you more flexibility to handle validation logic however you want.
- Lightweight and fast Regle is super lightweight, even with big forms, it won’t slow your app down.
- Async validation Support for async validation, perfect for checking data against servers or APIs.
- Extensible You can extend properties and add custom metadata to your validation rules.
Getting Started with Regle
Install Regle:
npm install @regle/core @regle/rules
App.vue:
<template>
<div class="h-screen bg-white dark:bg-[#191a19] text-gray-900 dark:text-gray-200 p-6">
<form @submit.prevent="submit" class="max-w-2xl mx-auto">
<div class="flex flex-col gap-4">
<!-- Full Name -->
<div class="flex flex-col gap-2">
<label required>Full Name</label>
<input v-model="form.fullName" type="text" class="border border-gray-300 dark:border-gray-700 dark:bg-neutral-600 dark:text-gray-200 rounded p-2" />
<FieldError :errors="r$.$errors.fullName" />
</div>
</div>
<!-- Children -->
<h3 class="font-semibold my-4">Children</h3>
<div v-for="(_, index) in form.children" class="border border-dashed border-gray-600 p-4 rounded-lg mt-4">
<h3 class="font-semibold uppercase text-xs text-gray-400 mb-3">
Child {{ index + 1 }}
</h3>
<div class="grid grid-cols-2 gap-x-6 gap-y-4">
<!-- Full Name -->
<div class="flex flex-col gap-2">
<label required>Full Name</label>
<input v-model="form.children[index].fullName" type="text" class="border border-gray-300 dark:border-gray-700 dark:bg-neutral-600 dark:text-gray-200 rounded p-2" />
<FieldError :errors="r$.$errors.children.$each[index].fullName" />
</div>
<!-- Age -->
<div class="flex flex-col gap-2">
<label required>Age</label>
<input v-model="form.children[index].age" type="number" class="border border-gray-300 dark:border-gray-700 dark:bg-neutral-600 dark:text-gray-200 rounded p-2" />
<FieldError :errors="r$.$errors.children.$each[index].age" />
</div>
</div>
</div>
<div class="flex items-center gap-4 mt-4">
<button type="submit" class="bg-green-800 text-white rounded py-2 px-5 hover:bg-green-900 transition hover:active:bg-green-950">
Submit
</button>
</div>
<div v-if="isFormValid" class="mt-4 text-green-600">
Form is valid!
</div>
</form>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import FieldError from './components/FieldError.vue'
import { minValue, minLength, required } from '@regle/rules'
import { useRegle, type RegleComputedRules } from '@regle/core'
const isFormValid = ref(false)
const form = ref({
fullName: '',
children: [
{ fullName: '', age: 0 },
{ fullName: '', age: 0 }
]
})
const rules = computed(() => {
return {
fullName: {
required,
minLength: minLength(10),
},
children: {
$each: {
fullName: {
required,
minLength: minLength(10),
},
age: {
required,
minValue: minValue(5),
}
}
}
} satisfies RegleComputedRules<typeof form>
})
const { r$ } = useRegle(form, rules)
const submit = async () => {
isFormValid.value = false
const { result } = await r$.$validate()
if (result) {
isFormValid.value = true
}
}
</script>
components/FieldError.vue
<template>
<ul class="text-sm text-red-400">
<li v-for="error of props.errors" :key="error" class="field-error">
* {{ error }}
</li>
</ul>
</template>
<script setup lang="ts">
const props = defineProps<{
errors: string[]
}>()
</script>
Top comments (0)