Skip to content

rForm

Form component which utilizes VeeValidate's useForm composable.

Props

NameTypeRequiredDescription
validationSchemaZodSchema<T>Zod validation schema for form
initalValuesPartial<T>Initial values for form fields
handleSubmit(values: GenericObject) => voidSubmit handler

Slots

NameDescriptionSlot props
headerUsed for title of the form
defaultMain content of the form, usually inputs
ctaPlace for action buttonsisSubmitting
footerPlace for any additional information

Code snippets

Example usage of rForm with rInput. Let's take for example login form:

  1. First we create our validation schema with Zod
  2. 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 of rInput 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" />

:::

Made with ♥️ by Riešenia