GuidesComponentsAuth ComponentsRegistrationexamples

Custom Validation

Learn how to implement custom validation rules for the registration form.

  • Stable unknown
  • Release candidate since 1.16.1-rc.3
  • Development since 1.16.1-dev.2111+9796905

Learn how to implement custom validation rules for the registration form.

Custom Validation Rules

Override default validation with custom Yup schemas:

import React from "react";
import * as Yup from "yup";
import { Register } from "@ovok/native";

export const CustomValidationRegistration = () => {
  const customValidations = {
    name: Yup.string()
      .required("First name is required")
      .min(3, "Name must be at least 3 characters")
      .max(20, "Name cannot exceed 20 characters")
      .matches(/^[a-zA-Z\s]+$/, "Name can only contain letters"),

    surname: Yup.string()
      .required("Last name is required")
      .min(2, "Last name must be at least 2 characters")
      .max(30, "Last name cannot exceed 30 characters"),

    email: Yup.string()
      .email("Please enter a valid email address")
      .required("Email is required")
      .matches(
        /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
        "Please enter a valid email format",
      ),

    password: (existingRule) =>
      existingRule
        .min(10, "Password must be at least 10 characters")
        .matches(/[A-Z]/, "Password must contain at least one uppercase letter")
        .matches(/[a-z]/, "Password must contain at least one lowercase letter")
        .matches(/[0-9]/, "Password must contain at least one number")
        .matches(
          /[^A-Za-z0-9]/,
          "Password must contain at least one special character",
        ),

    passwordConfirm: (existingRule) =>
      existingRule.required("Please confirm your password"),
  };

  return (
    <Register>
      <Register.Header>
        <Register.Header.Title>Create Strong Account</Register.Header.Title>
        <Register.Header.Description>
          Please follow our security requirements
        </Register.Header.Description>
      </Register.Header>

      <Register.EmailForm
        customValidations={customValidations}
        tenantCode="your-tenant-code"
        onSuccess={(response) => console.log("Success:", response)}
        onError={(error) => console.error("Error:", error)}
      >
        <Register.EmailForm.Inputs />
        <Register.EmailForm.RegisterButton />
      </Register.EmailForm>
    </Register>
  );
};

Domain-specific Validation

Validation rules for specific business requirements:

import React from "react";
import * as Yup from "yup";
import { Register } from "@ovok/native";

export const BusinessValidationRegistration = () => {
  // Custom validation for business domains
  const allowedDomains = ["company.com", "partner.org", "client.net"];

  const customValidations = {
    email: Yup.string()
      .email("Invalid email format")
      .required("Corporate email is required")
      .test("domain", "Please use a corporate email address", (value) => {
        if (!value) return false;
        const domain = value.split("@")[1];
        return allowedDomains.includes(domain);
      }),

    name: Yup.string()
      .required("Full name is required")
      .min(2, "Name too short")
      .test("full-name", "Please enter your full name", (value) => {
        return value && value.trim().split(" ").length >= 2;
      }),

    password: (existingRule) =>
      existingRule
        .min(12, "Corporate password must be at least 12 characters")
        .matches(/[A-Z]{2,}/, "Must contain at least 2 uppercase letters")
        .matches(/[0-9]{2,}/, "Must contain at least 2 numbers")
        .matches(/[!@#$%^&*]/, "Must contain special characters (!@#$%^&*)")
        .test("no-common", "Password is too common", (value) => {
          const commonPasswords = ["password123", "123456789", "qwerty123"];
          return !commonPasswords.includes(value?.toLowerCase());
        }),
  };

  return (
    <Register>
      <Register.Header>
        <Register.Header.Title>Corporate Registration</Register.Header.Title>
        <Register.Header.Description>
          Please use your corporate email address
        </Register.Header.Description>
      </Register.Header>

      <Register.EmailForm
        customValidations={customValidations}
        tenantCode="your-tenant-code"
        onSuccess={(response) =>
          console.log("Corporate registration:", response)
        }
        onError={(error) => console.error("Registration error:", error)}
      >
        <Register.EmailForm.Inputs />
        <Register.EmailForm.RegisterButton />
      </Register.EmailForm>
    </Register>
  );
};

Async Validation

Validate against server data (email uniqueness, etc.):

import React from "react";
import * as Yup from "yup";
import { Register } from "@ovok/native";

export const AsyncValidationRegistration = () => {
  // Mock API function to check email availability
  const checkEmailAvailability = async (email: string) => {
    // Simulate API call
    const response = await fetch(`/api/check-email?email=${email}`);
    const data = await response.json();
    return data.available;
  };

  const customValidations = {
    email: Yup.string()
      .email("Invalid email format")
      .required("Email is required")
      .test(
        "email-available",
        "This email is already registered",
        async (value) => {
          if (!value || !Yup.string().email().isValidSync(value)) {
            return true; // Let email format validation handle this
          }

          try {
            const isAvailable = await checkEmailAvailability(value);
            return isAvailable;
          } catch (error) {
            // If API fails, allow the form to proceed
            console.warn("Email availability check failed:", error);
            return true;
          }
        },
      ),

    name: Yup.string()
      .required("Username is required")
      .min(3, "Username must be at least 3 characters")
      .matches(
        /^[a-zA-Z0-9_]+$/,
        "Username can only contain letters, numbers, and underscores",
      )
      .test("username-available", "This username is taken", async (value) => {
        if (!value || value.length < 3) return true;

        try {
          const response = await fetch(`/api/check-username?username=${value}`);
          const data = await response.json();
          return data.available;
        } catch (error) {
          return true;
        }
      }),
  };

  return (
    <Register>
      <Register.Header>
        <Register.Header.Title />
        <Register.Header.Description />
      </Register.Header>

      <Register.EmailForm
        customValidations={customValidations}
        tenantCode="your-tenant-code"
        onSuccess={(response) => console.log("Success:", response)}
        onError={(error) => console.error("Error:", error)}
      >
        <Register.EmailForm.Inputs />
        <Register.EmailForm.RegisterButton />
      </Register.EmailForm>
    </Register>
  );
};

Password Strength Validation

Advanced password requirements with visual feedback:

import React from "react";
import * as Yup from "yup";
import { Register } from "@ovok/native";

export const StrongPasswordRegistration = () => {
  const customValidations = {
    password: (existingRule) =>
      existingRule
        .min(8, "Password must be at least 8 characters")
        .test(
          "password-strength",
          "Password does not meet requirements",
          (value) => {
            if (!value) return false;

            const requirements = [
              { test: /.{8,}/, message: "At least 8 characters" },
              { test: /[A-Z]/, message: "One uppercase letter" },
              { test: /[a-z]/, message: "One lowercase letter" },
              { test: /[0-9]/, message: "One number" },
              { test: /[^A-Za-z0-9]/, message: "One special character" },
            ];

            return requirements.every((req) => req.test.test(value));
          },
        ),

    passwordConfirm: (existingRule) =>
      existingRule
        .required("Please confirm your password")
        .test("passwords-match", "Passwords do not match", function (value) {
          return value === this.parent.password;
        }),
  };

  return (
    <Register>
      <Register.Header>
        <Register.Header.Title>Secure Registration</Register.Header.Title>
        <Register.Header.Description>
          Create a strong password to protect your account
        </Register.Header.Description>
      </Register.Header>

      <Register.EmailForm
        customValidations={customValidations}
        tenantCode="your-tenant-code"
        onSuccess={(response) => console.log("Success:", response)}
        onError={(error) => console.error("Error:", error)}
      >
        <Register.EmailForm.Inputs />
        <Register.EmailForm.RegisterButton />
      </Register.EmailForm>
    </Register>
  );
};

International Validation

Support for international names and addresses:

import React from "react";
import * as Yup from "yup";
import { Register } from "@ovok/native";

export const InternationalRegistration = () => {
  const customValidations = {
    name: Yup.string()
      .required("Name is required")
      .min(1, "Name is required")
      .max(50, "Name is too long")
      // Support international characters
      .matches(/^[\p{L}\p{M}\s\-'\.]+$/u, "Name contains invalid characters"),

    surname: Yup.string()
      .required("Surname is required")
      .min(1, "Surname is required")
      .max(50, "Surname is too long")
      .matches(
        /^[\p{L}\p{M}\s\-'\.]+$/u,
        "Surname contains invalid characters",
      ),

    email: Yup.string()
      .email("Invalid email format")
      .required("Email is required")
      // Support international domain names
      .matches(
        /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
        "Please enter a valid email address",
      ),
  };

  return (
    <Register>
      <Register.Header>
        <Register.Header.Title>
          International Registration
        </Register.Header.Title>
        <Register.Header.Description>
          Welcome users from around the world
        </Register.Header.Description>
      </Register.Header>

      <Register.EmailForm
        customValidations={customValidations}
        tenantCode="your-tenant-code"
        onSuccess={(response) => console.log("Success:", response)}
        onError={(error) => console.error("Error:", error)}
      >
        <Register.EmailForm.Inputs />
        <Register.EmailForm.RegisterButton />
      </Register.EmailForm>
    </Register>
  );
};

Validation Features

  • Real-time Validation: Validation occurs as the user types
  • Custom Error Messages: Provide specific, helpful error messages
  • Async Validation: Check against server data for uniqueness
  • Password Strength: Complex password requirements
  • International Support: Unicode character support for global users
  • Business Rules: Domain-specific validation requirements

Best Practices

  1. Clear Error Messages: Use descriptive, actionable error messages
  2. Progressive Validation: Start with basic rules, add complexity as needed
  3. User-Friendly: Balance security with usability
  4. Performance: Be mindful of async validation performance
  5. Accessibility: Ensure error messages are accessible to screen readers

Next Steps

Last updated on

On this page