Portal Community

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'],
  // ...
};