Skip to content

Custom Schemas

Schema Validation

vue
<script lang="ts" setup>
import { useValibotSchema } from 'vue-formor';
import { nullish, object, string, custom } from 'valibot';

const schema = useValibotSchema(
  object({
    name: nullish(
      string([
        minLength(1, msgs.required),
        custom((input) => /^[A-Za-z]+$/.test(input), msgs.letters),
      ]),
      '',
    ),
  }),
  toRef(state, 'myForm'),
  toRef(state, 'myValdn'),
);
</script>
vue
<script lang="ts" setup>
import { useZodSchema } from 'vue-formor';
import { z } from 'zod';

const schema = useZodSchema(
  z.object({
    name: z
      .string({ required_error: msgs.required })
      .nonempty(msgs.required)
      .refine((val) => {
        if (val) return /^[A-Za-z]+$/.test(val);
        return true;
      }, msgs.letters),
  }),
  toRef(state, 'myForm'),
  toRef(state, 'myValdn'),
);
</script>
vue
<script lang="ts" setup>
import { useYupSchema } from 'vue-formor';
import { object, string } from 'yup';

const schema = useYupSchema(
  object({
    name: string()
      .required(msgs.required)
      .test('letters', msgs.letters, (value) => {
        if (value && !/^[A-Za-z]+$/.test(value)) return false;
        return true;
      }),
  }),
  toRef(state, 'myForm'),
  toRef(state, 'myValdn'),
);
</script>

Final Code

vue
<script lang="ts" setup>
import { reactive, toRef } from 'vue';
import { useValibotSchema } from 'vue-formor';
import { nullish, object, string, custom } from 'valibot';

interface CustomSchemas {
  name: string;
}

const state = reactive({
  myForm: {} as CustomSchemas,
  myValdn: {} as Record<string, string>,
});

const msgs = {
  required: `This is a required field`,
  letters: `This must contain only letters`,
};

const schema = useValibotSchema(
  object({
    name: nullish(
      string([
        minLength(1, msgs.required),
        custom((input) => /^[A-Za-z]+$/.test(input), msgs.letters),
      ]),
      '',
    ),
  }),
  toRef(state, 'myForm'),
  toRef(state, 'myValdn'),
);

const submit = () => {
  if (schema.validate()) {
    // passed
  }
};
</script>

<template>
  <fieldset>
    <legend>Custom Schemas</legend>

    <form>
      <div class="flex gap-2">
        <label for="name">Name:</label>
        <input id="name" v-model="state.myForm.name" type="text" />
        <div class="text-red-500">{{ state.myValdn.name }}</div>
      </div>

      <button type="button" @click="submit">Submit</button>
    </form>

    <pre>{{ state.myForm }}</pre>

    <pre>{{ state.myValdn }}</pre>
  </fieldset>
</template>

<style scoped>
.flex {
  display: flex;
}

.gap-2 {
  gap: 0.5rem;
}

.text-red-500 {
  --un-text-opacity: 1;
  color: rgba(239, 68, 68, var(--un-text-opacity));
}
</style>
vue
<script lang="ts" setup>
import { reactive, toRef } from 'vue';
import { useZodSchema } from 'vue-formor';
import { z } from 'zod';

interface CustomSchemas {
  name: string;
}

const state = reactive({
  myForm: {} as CustomSchemas,
  myValdn: {} as Record<string, string>,
});

const msgs = {
  required: `This is a required field`,
  letters: `This must contain only letters`,
};

const schema = useZodSchema(
  z.object({
    name: z
      .string({ required_error: msgs.required })
      .nonempty(msgs.required)
      .refine((val) => {
        if (val) return /^[A-Za-z]+$/.test(val);
        return true;
      }, msgs.letters),
  }),
  toRef(state, 'myForm'),
  toRef(state, 'myValdn'),
);

const submit = () => {
  if (schema.validate()) {
    // passed
  }
};
</script>

<template>
  <fieldset>
    <legend>Custom Schemas</legend>

    <form>
      <div class="flex gap-2">
        <label for="name">Name:</label>
        <input id="name" v-model="state.myForm.name" type="text" />
        <div class="text-red-500">{{ state.myValdn.name }}</div>
      </div>

      <button type="button" @click="submit">Submit</button>
    </form>

    <pre>{{ state.myForm }}</pre>

    <pre>{{ state.myValdn }}</pre>
  </fieldset>
</template>

<style scoped>
.flex {
  display: flex;
}

.gap-2 {
  gap: 0.5rem;
}

.text-red-500 {
  --un-text-opacity: 1;
  color: rgba(239, 68, 68, var(--un-text-opacity));
}
</style>
vue
<script lang="ts" setup>
import { reactive, toRef } from 'vue';
import { useYupSchema } from 'vue-formor';
import { object, string } from 'yup';

interface CustomSchemas {
  name: string;
}

const state = reactive({
  myForm: {} as CustomSchemas,
  myValdn: {} as Record<string, string>,
});

const msgs = {
  required: `This is a required field`,
  letters: `This must contain only letters`,
};

const schema = useYupSchema(
  object({
    name: string()
      .required(msgs.required)
      .test('letters', msgs.letters, (value) => {
        if (value && !/^[A-Za-z]+$/.test(value)) return false;
        return true;
      }),
  }),
  toRef(state, 'myForm'),
  toRef(state, 'myValdn'),
);

const submit = () => {
  if (schema.validate()) {
    // passed
  }
};
</script>

<template>
  <fieldset>
    <legend>Custom Schemas</legend>

    <form>
      <div class="flex gap-2">
        <label for="name">Name:</label>
        <input id="name" v-model="state.myForm.name" type="text" />
        <div class="text-red-500">{{ state.myValdn.name }}</div>
      </div>

      <button type="button" @click="submit">Submit</button>
    </form>

    <pre>{{ state.myForm }}</pre>

    <pre>{{ state.myValdn }}</pre>
  </fieldset>
</template>

<style scoped>
.flex {
  display: flex;
}

.gap-2 {
  gap: 0.5rem;
}

.text-red-500 {
  --un-text-opacity: 1;
  color: rgba(239, 68, 68, var(--un-text-opacity));
}
</style>

Released under the MIT License.