Atlas Forms
Adding Custom Validators
Custom validators are registered separately from custom controls using registerValidator(name, fn). They become available in form schemas via the customRule validation property. Pack validators alongside your controls in the same library.
Validator Function Signature
type ValidatorFunction = (
value: any,
options?: Record<string, any>
) => { valid: boolean; message?: string };
// Or async
type AsyncValidatorFunction = (
value: any,
options?: Record<string, any>
) => Promise<{ valid: boolean; message?: string }>;
Phone Number Validator
// src/validators/phoneValidator.ts
export const phoneValidator = (value: any): { valid: boolean; message?: string } => {
if (!value) return { valid: true }; // Let 'required' handle empty values
// E.164 format: +[country][number], 7-15 digits
const e164 = /^\+[1-9]\d{6,14}$/;
// Common formats: (555) 000-0000, 555-000-0000, 5550000000
const national = /^[\d\s\-\(\)]{7,15}$/;
if (e164.test(value) || national.test(value)) {
return { valid: true };
}
return { valid: false, message: 'Please enter a valid phone number' };
};
Async Validator — Email Availability
// src/validators/emailAvailableValidator.ts
export const emailAvailableValidator = async (
value: any
): Promise<{ valid: boolean; message?: string }> => {
if (!value || typeof value !== 'string') return { valid: true };
const response = await fetch(`/api/auth/check-email?email=${encodeURIComponent(value)}`);
const data = await response.json();
return data.available
? { valid: true }
: { valid: false, message: 'This email is already registered' };
};
Registering Validators
import { registerValidator } from '@atlas-forms/validation-js';
import { phoneValidator } from './validators/phoneValidator';
import { postalCodeValidator } from './validators/postalCodeValidator';
import { emailAvailableValidator } from './validators/emailAvailableValidator';
export function registerContactControls(): void {
// Register controls...
// Register validators
registerValidator('phone', phoneValidator);
registerValidator('postalCode', postalCodeValidator);
registerValidator('emailAvailable', emailAvailableValidator);
}
Using in Form Schema
{
"id": "phone-number",
"type": "myorg:phone-input",
"label": "Phone Number",
"validation": {
"required": true,
"customRule": "phone",
"message": "Please enter a valid phone number"
}
}
Declaring Supported Validators on the Plugin
To make the Form Studio property panel show the correct validator options for your control, declare which validators it supports:
export const phoneInputPlugin: ReactControlPlugin = {
type: 'myorg:phone-input',
label: 'Phone Number',
group: 'input',
supportedValidators: ['required', 'phone', 'postalCode'],
// ...
};