rForm
Form component which utilizes VeeValidate's useForm
composable.
Props
Name | Type | Required | Description |
---|---|---|---|
validationSchema | ZodSchema<T> | ✅ | Zod validation schema for form |
initalValues | Partial<T> | ❌ | Initial values for form fields |
handleSubmit | (values: GenericObject) => void | ✅ | Submit handler |
Slots
Name | Description | Slot props |
---|---|---|
header | Used for title of the form | |
default | Main content of the form, usually inputs | |
cta | Place for action buttons | isSubmitting |
footer | Place for any additional information |
Code snippets
Example usage of rForm
with rInput
. Let's take for example login form:
- First we create our validation schema with
Zod
- Then we create our form using
rForm
ts
import { z } from "zod";
export const signInFormSchema = z.object({
email: z
.string()
.min(1, { message: "E-mail je povinný" })
.email({ message: "Nesprávny formát emailu" }),
password: z.string().min(1, { message: "Heslo je povinné" }),
});
export type TSignInFormSchema = z.infer<typeof signInFormSchema>;
vue
<script setup lang="ts">
// Import validation schema "formSchema.ts"
import { signInFormSchema, type TSignInFormSchema } from "./formSchema";
import type { GenericObject } from "vee-validate";
// Get form instace to call `validate()` in submitHandler
const signInForm = useTemplateRef("signInForm");
// Define initial form state [Optional]
const initialFormState = {
email: "",
password: "",
} satisfies TSignInFormSchema;
// Submit handler
const onSubmit = async (values: GenericObject) => {
try {
await signInForm.value?.form.validate();
} catch (error) {
console.log(error);
}
};
</script>
<template>
<RForm
ref="signInForm"
class="c-sign-in-form"
:validation-schema="signInFormSchema"
:handle-submit="onSubmit"
:initial-values="initialFormState"
>
<template #header>
<h2 class="c-sign-in-form__title">Prihlásenie</h2>
</template>
// Form inputs
<div class="c-sign-in-form__inputs">
<RInput id="signInEmail" name="email" label="E-mail" type="email" />
<RInput
id="signInPassword"
name="password"
label="Heslo"
type="password"
/>
</div>
<template #cta="{ isSubmitting }">
<RButton :is-loading="isSubmitting.value">
Sign In
</RButton>
</template>
<template #footer>
/* Any additional info */
</template>
</RForm>
</template>
⚠️ Value of rInput
's name
attribute
- For validation to work, the
name
attribute ofrInput
has to be the same as in your validation shcema
What about nested fields?
- Let's look at case when you have fields nested in object. We will use the example above and update it a little bit:
ts
export const signInFormSchema = z.object({
accountDetails: z.object({
email: z
.string()
.min(1, { message: "E-mail je povinný" })
.email({ message: "Nesprávny formát emailu" }),
}),
password: z.string().min(1, { message: "Heslo je povinné" }),
});
vue
<!-- `rInput` usage with new structure of validation schema -->
<RInput id="signInEmail" name="accountDetails.email" label="E-mail" type="email" />
:::