Custom Validation
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
- Clear Error Messages: Use descriptive, actionable error messages
- Progressive Validation: Start with basic rules, add complexity as needed
- User-Friendly: Balance security with usability
- Performance: Be mindful of async validation performance
- Accessibility: Ensure error messages are accessible to screen readers
Next Steps
- Custom Styling - Style validation states and error messages
- Pre-filled Data - Handle validation with default values