ForgeForm

Forgeform

Lightweight, TypeScript-First Form Validation for Modern Web Applications

Support for Bun, Deno, React Native, and Expo is coming soon. If you encounter any issues, please open a ticket on GitHub. We are actively working to enhance support for these platforms.

Introduction

ForgeForm is a powerful and intuitive form validation library built with TypeScript for robust web application development. It simplifies form validation with its declarative schema definition (dsl), comprehensive validation engine, React integration for easy form state management, and a rich regex builder.

Getting Started

Install ForgeForm using npm or yarn:

npm install forgeform
yarn add forgeform

Features

Intuitive DSL (Domain Specific Language)

Define form schemas effortlessly using createSchema with a clean, JSON-like syntax. ForgeForm's DSL is designed to be highly readable and intuitive, allowing you to quickly define complex form structures and validation rules without writing verbose imperative code.

Key Aspects of the DSL:

  • createSchema for Schema Definition: The core of ForgeForm's DSL is the createSchema function. It accepts a generic type parameter to strongly type your form data and an options object to define your schema. The schema definition closely resembles JSON, making it easy to understand and write.

  • Wide Range of Built-in Field Types: ForgeForm provides a comprehensive set of field types to cover common form input scenarios. You can declare fields as:

    • Primitives: string, number, boolean, email, password, url, tel, color, date-only.
    • Choice Types: enum (for dropdown/select).
    • Text Areas: textarea (for multi-line text input).

    Each field type comes with a set of built-in validation rules and customization options (like error messages, trim, lowercase, min, max, pattern, etc.), reducing the need for manual validation logic in many cases.

  • Handles Complex Data Structures: ForgeForm schemas can effortlessly manage complex form data, including:

    • Nested Objects: Define fields that are objects themselves, allowing you to structure your form data hierarchically.
    • Arrays: Represent lists of data within your form, useful for handling repeatable sections or collections of items.
  • Advanced Type Support (Future Enhancement): While the current version focuses on core field types, ForgeForm is designed to be extensible and plans to incorporate advanced type support in future releases, potentially including:

    • union types: To allow a field to accept values of multiple types.
    • literal types: To restrict field values to a specific set of literal values (e.g., "light" | "dark" for theme selection).
    • tuple types: To define fixed-length arrays with specific types for each element.
    • record types: To define key-value maps with specific key and value types.

Schema Declaration Example:

import { createSchema } from 'forgeform';
 
interface ComplexFormData {
  fullName?: string;
  email?: string;
  age?: number;
  website?: string;
  isSubscribed?: boolean;
  themePreference?: 'light' | 'dark' | 'system';
  address?: {
    street?: string;
    city?: string;
    zipCode?: string;
  };
  tags?: string[];
}
 
const complexFormSchema = createSchema<ComplexFormData>({
  fields: {
    fullName: { type: 'string', required: true, minLength: 2, maxLength: 100, requiredErrorMessage: 'Name is required', minLengthErrorMessage: 'Name too short', maxLengthErrorMessage: 'Name too long' },
    email: { type: 'email', required: true, formatErrorMessage: 'Invalid email format', requiredErrorMessage: 'Email is required' },
    age: { type: 'number', min: 18, max: 99, minErrorMessage: 'Must be 18+', maxErrorMessage: 'Age limit exceeded' },
    website: { type: 'url', formatErrorMessage: 'Invalid URL' },
    isSubscribed: { type: 'boolean', default: false },
    themePreference: { type: 'enum', enum: ['light', 'dark', 'system'], default: 'system', requiredErrorMessage: 'Theme selection required' },
    address: {
      type: 'object', // Nested object field
      fields: {
        street: { type: 'string', required: true, requiredErrorMessage: 'Street is required' },
        city: { type: 'string', required: true, requiredErrorMessage: 'City is required' },
        zipCode: { type: 'string', pattern: /^\d{5}(-\d{4})?$/, patternErrorMessage: 'Invalid ZIP code' },
      },
    },
    tags: {
      type: 'array', // Array of strings
      items: { type: 'string' },
    },
  },
});

Robust Core Validation Engine

ForgeForm is built upon a robust and reliable validation engine, ensuring data integrity and providing comprehensive validation capabilities for your forms.

  • Type-Safe Validation: ForgeForm enforces type-safe validation, guaranteeing that the data you collect adheres to the types you explicitly define in your schema. When you define a field as a number, ForgeForm ensures that the validated value is indeed a number, preventing type-related errors and ensuring data consistency.

    import { createSchema } from 'forgeform';
     
    interface NumberFormData {
      quantity?: number;
    }
     
    const numberSchema = createSchema<NumberFormData>({
      fields: {
        quantity: { type: 'number', required: true, min: 1, requiredErrorMessage: 'Quantity is required', minErrorMessage: 'Quantity must be at least 1' },
      },
    });

    In this schema, quantity is defined as a number type. ForgeForm will ensure that the value provided for quantity is a valid number and meets the specified min validation rule. If a non-numeric value is provided, or if the value violates the type constraint, validation will fail with a type-related error.

  • Built-in Sanitization: ForgeForm automatically applies built-in sanitization to string-based field types, helping you ensure clean and consistent data without manual preprocessing.

    • Whitespace Trimming: By default, ForgeForm trims whitespace from the beginning and end of string inputs. This removes accidental spaces that users might enter, ensuring cleaner data storage and comparison. You can disable trimming if needed by setting trim: false in your field definition.

      import { createSchema } from 'forgeform';
       
      interface StringFormData {
        username?: string;
        untrimmedInput?: string;
      }
       
      const stringSchema = createSchema<StringFormData>({
        fields: {
          username: { type: 'string', required: true, trim: true, requiredErrorMessage: 'Username is required' }, // Trimmed by default
          untrimmedInput: { type: 'string', trim: false }, // Trimming disabled for this field
        },
      });
    • Case Conversion: ForgeForm can automatically convert the case of string inputs to either lowercase or uppercase. This is useful for standardizing data like usernames or emails where case-insensitivity is desired. Use lowercase: true or uppercase: true in your field definition to enable case conversion.

      import { createSchema } from 'forgeform';
       
      interface CaseFormData {
        email?: string;
        productCode?: string;
      }
       
      const caseSchema = createSchema<CaseFormData>({
        fields: {
          email: { type: 'email', required: true, lowercase: true, requiredErrorMessage: 'Email is required' }, // Converted to lowercase
          productCode: { type: 'string', uppercase: true }, // Converted to uppercase
        },
      });
    • React Hook Form Resolver Sanitization: When using ForgeForm with React Hook Form through the provided resolver, sanitization rules defined in your ForgeForm schema are seamlessly applied during the validation process within React Hook Form. This means that as users interact with your form, the data is automatically sanitized according to your schema rules before validation and submission. This integration ensures consistent data handling and validation logic across your form workflows when using React Hook Form. (See Resolver documentation for details)

    • Regex/Format Validation: ForgeForm provides built-in regex patterns for common formats, and allows custom regex for more specific needs.

      import { createSchema } from 'forgeform';
       
      interface FormatFormData {
        emailAddress?: string;
        website?: string;
        phoneNumber?: string;
        zip?: string;
      }
       
      const formatSchema = createSchema<FormatFormData>({
        fields: {
          emailAddress: { type: 'email', formatErrorMessage: 'Invalid email format' },
          website: { type: 'url', formatErrorMessage: 'Invalid URL format' },
          phoneNumber: { type: 'tel', patternErrorMessage: 'Invalid phone number format' },
          zip: { type: 'string', pattern: /^\d{5}(-\d{4})?$/, patternErrorMessage: 'Invalid ZIP code format' }, // Custom ZIP pattern example
        },
      });

      In this example, ForgeForm will use built-in regex patterns to validate emailAddress, website (http, https), and phoneNumber.

      For zip, a custom regex pattern is provided to match a specific ZIP code format.

  • Custom Validators: When built-in validations are not sufficient, ForgeForm allows you to define custom validators. These are functions that provide complete control over validation logic, enabling you to implement complex, conditional, or cross-field validation rules.

    • Synchronous Validators: For immediate, client-side validation, you can create synchronous custom validators. These functions receive the field value and optionally the entire form data and should return an error message string if validation fails, or undefined if validation passes.

      import { createSchema } from 'forgeform';
       
      interface CustomValidationData {
        couponCode?: string;
        totalPrice?: number;
      }
       
      const customSyncSchema = createSchema<CustomValidationData>({
        fields: {
          couponCode: {
            type: 'string',
            customValidator: (value, formData) => {
              if (value === 'DISCOUNT20' && formData?.totalPrice < 100) {
                return 'Coupon DISCOUNT20 is only valid for orders over $100.';
              }
              return undefined; // No error
            },
            customErrorMessage: 'Coupon code validation failed' // Optional custom error message key
          },
          totalPrice: { type: 'number' }, // For context in custom validation
        },
      });
    • Asynchronous Validators: For validations that require external data or time-consuming operations (e.g., checking database for username availability), ForgeForm supports asynchronous custom validators. These functions should return a Promise that resolves to an error message string (if invalid) or undefined (if valid).

      import { createSchema } from 'forgeform';
       
      interface AsyncValidationData {
        username?: string;
      }
       
      const customAsyncSchema = createSchema<AsyncValidationData>({
        fields: {
          username: {
            type: 'string', required: true, requiredErrorMessage: 'Username is required',
            customValidator: async (value) => {
              // Simulate API call to check username availability
              await new Promise(resolve => setTimeout(resolve, 500)); // Simulate delay
              if (value === 'takenUsername') {
                return 'Username is already taken.';
              }
              return undefined; // No error
            },
            customErrorMessage: 'Username availability check failed' // Optional custom error message key
          },
        },
      });
    • Customizable Error Messages: ForgeForm allows you to tailor error messages to provide more user-friendly and context-specific feedback. For each validation rule, you can define custom error messages (e.g., requiredErrorMessage, minLengthErrorMessage, formatErrorMessage, customErrorMessage). If custom messages are not provided, ForgeForm provides sensible default error messages.

      import { createSchema } from 'forgeform';
       
      interface CustomErrorMessagesData {
        firstName?: string;
        emailAddress?: string;
      }
       
      const customMessageSchema = createSchema<CustomErrorMessagesData>({
        fields: {
          firstName: { type: 'string', required: true, requiredErrorMessage: 'Please enter your first name.' },
          emailAddress: { type: 'email', required: true, formatErrorMessage: 'Please enter a valid email address.' },
        },
      });

Seamless Integration with React Hook Form

ForgeForm offers seamless integration with React Hook Form, a popular library for form state management in React. By using ForgeForm's specialized resolver, you can effortlessly connect your ForgeForm schemas to React Hook Form, leveraging the strengths of both libraries for a streamlined form development experience.

  • forgeFormResolver: The key to this integration is the forgeFormResolver function. This resolver acts as a bridge, enabling React Hook Form to utilize ForgeForm schemas for validation. It handles the process of transforming ForgeForm schema validation results into a format that React Hook Form understands, making the integration smooth and efficient.

    • Regex/Format Validation: ForgeForm provides built-in regex patterns for common formats, and allows custom regex for more specific needs.

      // src/components/ReactHookFormExample.tsx
      import React from 'react';
      import { useForm } from 'react-hook-form';
      import { createSchema, forgeFormResolver } from 'forgeform';
       
      interface HookFormData {
        name?: string;
        email?: string;
      }
       
      // 1. Define your ForgeForm schema
      const hookFormSchema = createSchema<HookFormData>({
        fields: {
          name: { type: 'string', required: true, minLength: 2, requiredErrorMessage: 'Name is required', minLengthErrorMessage: 'Name must be at least 2 characters' },
          email: { type: 'email', required: true, requiredErrorMessage: 'Email is required', formatErrorMessage: 'Invalid email format' },
        },
      });
       
      const ReactHookFormExample = () => {
        // 2. Use React Hook Form's useForm with forgeFormResolver
        const { register, handleSubmit, formState: { errors } } = useForm<HookFormData>({
          resolver: forgeFormResolver(hookFormSchema),
        });
       
        const onSubmit = (data: HookFormData) => {
          alert('Form Data in Console (React Hook Form + ForgeForm)');
          console.log('Form Data:', data);
        };
       
        return (
          <form onSubmit={handleSubmit(onSubmit)}>
            <div>
              <label htmlFor="name">Name:</label>
              <input {...register('name')} id="name" />
              {errors.name && <p style={{ color: 'red' }}>{errors.name.message}</p>}
            </div>
            <div>
              <label htmlFor="email">Email:</label>
              <input {...register('email')} type="email" id="email" />
              {errors.email && <p style={{ color: 'red' }}>{errors.email.message}</p>}
            </div>
            <button type="submit">Submit</button>
          </form>
        );
      };
       
      export default ReactHookFormExample;

      Explanation of the Integration:

      Import Necessary Modules:

      import { useForm } from 'react-hook-form';
      import { createSchema, forgeFormResolver } from 'forgeform';
      • Import useForm from react-hook-form to manage form state and submission.
      • Import createSchema to define your validation schema using ForgeForm.
      • Import forgeFormResolver to bridge ForgeForm and React Hook Form.

      Define ForgeForm Schema:

      const hookFormSchema = createSchema<HookFormData>({...});
      • Create your validation schema using createSchema as you normally would in ForgeForm, defining fields and their validation rules.

      Use useForm with forgeFormResolver:

      const { register, handleSubmit, formState: { errors } } = useForm<HookFormData>({
        resolver: forgeFormResolver(hookFormSchema),
      });
      • Initialize React Hook Form using useForm<HookFormData>(), specifying the type of your form data.
      • Crucially, set the resolver option in useForm to forgeFormResolver(hookFormSchema). This tells React Hook Form to use ForgeForm's validation engine and schema for form validation. Pass your hookFormSchema as an argument to forgeFormResolver.

      Register Input Fields:

      <input {...register('name')} id="name" />
      <input {...register('email')} type="email" id="email" />
      • Use the register function from useForm to register your input fields. Spread the result of register('fieldName') onto your input elements ({...register('name')}). This connects React Hook Form's state management and validation to your input fields.

      Handle Form Submission:

      const onSubmit = (data: HookFormData) => { ... };
      // ...
      <form onSubmit={handleSubmit(onSubmit)}>
      • Use handleSubmit(onSubmit) from useForm to handle form submission. React Hook Form will automatically trigger validation based on your ForgeForm schema before calling your onSubmit function. The onSubmit function will receive the validated form data.

      Display Errors:

      {errors.name && <p style={{ color: 'red' }}>{errors.name.message}</p>}
      {errors.email && <p style={{ color: 'red' }}>{errors.email.message}</p>}
      • Access validation errors through formState.errors returned by useForm. React Hook Form will populate the errors object with any validation errors based on your ForgeForm schema. Display these errors in your UI as needed, typically below the corresponding input fields. errors.fieldName.message will contain the error message defined in your ForgeForm schema.

      Benefits of Integration:

      • Unified Validation Logic: Define your validation rules once in your ForgeForm schema and reuse them seamlessly with React Hook Form for form state management.
      • Leverage React Hook Form Features: Benefit from React Hook Form's performant form state management, easy form submission handling, and optimized re-renders.
      • Simplified Form Code: Reduce boilerplate code by combining declarative schema-based validation from ForgeForm with React Hook Form's form handling capabilities.
      • Consistent Validation: Ensure consistent validation logic across your application by using the same ForgeForm schemas whether you are using React Hook Form or managing form state directly with ForgeForm's utilities.

Wizard Forms (Multi-Step Forms) (New in v1.2.2)

ForgeForm now includes a powerful Wizard Forms feature, enabling the creation of multi-step forms with ease. Wizard Forms are ideal for complex data collection processes, guiding users through a sequence of steps while managing state, validation, and navigation seamlessly.

Key Features of Wizard Forms:

  • Step-Based Structure: Divide complex forms into logical steps, each with its own schema and validation rules. This improves user experience by breaking down lengthy forms into manageable chunks.

  • Step Identifiers (id): Each step in a wizard is defined with a unique id. This id allows you to programmatically reference and control specific steps, making wizard management more flexible.

    const steps = [
      { id: 'step-personal-info', schema: personalInfoSchema },
      { id: 'step-address-details', schema: addressSchema },
      { id: 'step-confirmation', schema: confirmationSchema },
    ];

    In this steps array, 'step-personal-info', 'step-address-details', and 'step-confirmation' are step identifiers.

  • Granular Validation: Validate each step independently as the user progresses through the wizard. This ensures that users are only prompted to correct errors in the current step, streamlining the form completion process. Validation is triggered when moving to the next step or submitting the final step.

  • Lifecycle Callbacks: ForgeForm Wizards provide a rich set of lifecycle callbacks, allowing you to hook into key moments in the wizard flow and execute custom logic:

    • onStepChange(stepId, index): Called whenever the active step changes. Provides the stepId of the new step and its index (0-based). Useful for updating UI elements like progress indicators or step titles.
    • onValidationSuccess(stepId, data): Invoked after a step is successfully validated (when calling nextStep). Provides the stepId and the validated data for the step. You can use this to perform actions after successful step validation, like saving step data or updating UI.
    • onValidationError(stepId, errors): Called when validation fails for a step (when calling nextStep). Provides the stepId and the errors object containing validation errors for the step. Use this to display step-specific error messages or prevent navigation to the next step.
    • onComplete(finalData): Triggered when the wizard is successfully completed (all steps validated and submitted). Provides the finalData, which is an aggregation of data from all steps in the wizard. This is where you would typically handle final form submission, like sending data to a server.

    These callbacks are configured within the options object when creating the wizard:

    const wizard = createWizard(steps, initialData, {
      onStepChange: (stepId, index) => console.log(`Step changed to: ${stepId}, index: ${index}`),
      onValidationSuccess: (stepId, data) => console.log(`Step ${stepId} validated successfully with data:`, data),
      onValidationError: (stepId, errors) => console.error(`Validation failed for step ${stepId} with errors:`, errors),
      onComplete: (finalData) => console.log('Wizard Completed! Final Data:', finalData),
    });
  • Progress Tracking & State Persistence: ForgeForm Wizard automatically manages the wizard's state, including the current step, step history, and accumulated data.

    • Progress Tracking: The wizard instance maintains the currentStepIndex (0-based index of the current step) and totalSteps properties, allowing you to easily track user progress and display progress indicators in your UI.
    • State Persistence (within component lifecycle): The wizard instance retains the data collected across steps throughout the component's lifecycle. You can access the accumulated data at any point using wizard.data. If needed, you can also extend this to persist the state across sessions (e.g., using local storage) and re-hydrate the wizard later (feature to be explored in future updates).
  • reset() Method: The wizard.reset() method allows you to reset the wizard to its initial state, clearing all data and returning to the first step.

Wizard Forms

Creating a 3-Step Wizard (check wizard page for detailed example)

ReactForm State Management

ForgeForm provides utilities to simplify form state management even when not using React Hook Form directly. While ForgeForm excels at validation, it also offers basic form state handling to streamline development for scenarios where a full-fledged form library might be overkill.

  • Simplifies Form State: ForgeForm helps manage form data and validation errors in a structured manner, reducing the need for manual state management with useState for each input in simple forms.

  • Manages Form Data and Validation Errors Seamlessly: ForgeForm's validate method not only validates data but also returns both validation success status and any errors encountered. This structured output helps in easily managing form data and displaying errors in your UI.

    import React, { useState } from 'react';
    import { createSchema } from 'forgeform';
     
    interface ContactFormData {
      fullName?: string;
      message?: string;
    }
     
    const contactSchema = createSchema<ContactFormData>({
      fields: {
        fullName: { type: 'string', required: true, requiredErrorMessage: 'Your name is required' },
        message: { type: 'textarea', required: true, minLength: 20, requiredErrorMessage: 'Message is required', minLengthErrorMessage: 'Message must be at least 20 characters' },
      },
    });
     
    const FormStateManagementExample = () => {
      const [formData, setFormData] = useState<ContactFormData>({});
      const [formErrors, setFormErrors] = useState({});
     
      const handleChange = (e) => {
        setFormData({ ...formData, [e.target.name]: e.target.value });
      };
     
      const handleSubmit = async (e) => {
        e.preventDefault();
        const validationResult = await contactSchema.validate(formData);
        if (validationResult.success) {
          alert('Form Validated! (Check console for data)');
          console.log('Form Data:', formData);
          setFormErrors({}); // Clear errors on success
        } else {
          setFormErrors(validationResult.errors); // Set errors for display
          alert('Validation Failed. See errors below.');
        }
      };
     
      return (
        <form onSubmit={handleSubmit}>
          <div>
            <label htmlFor="fullName">Full Name:</label>
            <input type="text" id="fullName" name="fullName" onChange={handleChange} />
            {formErrors.fullName && <p style={{ color: 'red' }}>{formErrors.fullName.error}</p>}
          </div>
          <div>
            <label htmlFor="message">Message:</label>
            <textarea id="message" name="message" onChange={handleChange} />
            {formErrors.message && <p style={{ color: 'red' }}>{formErrors.message.error}</p>}
          </div>
          <button type="submit">Submit</button>
        </form>
      );
    };
     
    export default FormStateManagementExample;

    In this example, formData and formErrors states are managed alongside ForgeForm validation to handle form input and error display.

  • Handles Nested Form Fields (Dot Notation): ForgeForm seamlessly handles nested form data structures using dot notation in field names within your schema. For instance, you can define fields like "address.street" and "address.city" to represent nested address information within your form data. Validation and data access work intuitively with these dot-notated field paths.

    import { createSchema } from 'forgeform';
     
    interface NestedFormData {
      name?: string;
      address?: {
        street?: string;
        city?: string;
        zipCode?: string;
      };
    }
     
    const nestedFormSchema = createSchema<NestedFormData>({
      fields: {
        name: { type: 'string', required: true, requiredErrorMessage: 'Name is required' },
        'address.street': { type: 'string', required: true, requiredErrorMessage: 'Street is required' },
        'address.city': { type: 'string', required: true, requiredErrorMessage: 'City is required' },
        'address.zipCode': { type: 'string', pattern: /^\d{5}(-\d{4})?$/, patternErrorMessage: 'Invalid Zip Code' },
      },
    });

    When validating data against nestedFormSchema, ForgeForm correctly interprets and validates the nested address object and its fields.

  • Real-time Validation Feedback: Although the examples so far have shown validation on submit, you can easily implement real-time validation feedback (validation on input change or field blur) by calling schema.validate within your input change handlers and updating the formErrors state accordingly. This provides users with immediate feedback as they fill out the form, improving usability.

Comprehensive Regex Builder

ForgeForm includes a Comprehensive Regex Builder to simplify and enhance regex-based validation. It provides a library of over 100 pre-built, RCN-compliant regex patterns and a buildRegex function for creating custom regex patterns.

  • Over 100 Pre-built RCN Regex Patterns: ForgeForm comes loaded with over 100 ready-to-use regular expressions that conform to RCN (Relaxed Character Normalization) standards. These patterns cover a wide range of common validation formats, including:

    Regex Builder

    Even though we have a good regex library for all purposes, for more complex projects it's better to add your own custom regex.
    • email: Validates standard email addresses.
    • phone: Validates various international and domestic phone number formats.
    • url: Validates web URLs (HTTP/HTTPS).
    • uuid: Validates UUID (Universally Unique Identifier) formats.
    • zip: Validates ZIP codes (US and international variations).
    • ip: Validates IPv4 and IPv6 addresses.
    • date: Validates various date formats (ISO, common date strings).
    • time: Validates time formats (12-hour, 24-hour).
    • creditCard: Validates common credit card number formats.
    • color: Validates hexadecimal color codes.
    • ... and many more (currency, social security numbers, etc.).

    To use these pre-built patterns, simply select the corresponding field type in your schema (e.g., type: 'email', type: 'url', type: 'tel'). ForgeForm automatically applies the appropriate regex pattern for validation.

    import { createSchema } from 'forgeform';
     
    interface RegexExampleFormData {
      emailAddress?: string;
      websiteUrl?: string;
      phoneNumber?: string;
    }
     
    const regexExampleSchema = createSchema<RegexExampleFormData>({
      fields: {
        emailAddress: { type: 'email', required: true, requiredErrorMessage: 'Email is required', formatErrorMessage: 'Invalid email format' }, // Uses pre-built email regex
        websiteUrl: { type: 'url', formatErrorMessage: 'Invalid URL' }, // Uses pre-built URL regex
        phoneNumber: { type: 'tel', patternErrorMessage: 'Invalid phone number' }, // Uses pre-built phone regex
      },
    });
  • buildRegex Function for Custom Regex: For validation scenarios that require more specific or custom regular expressions not covered by the pre-built patterns, ForgeForm provides the buildRegex utility function. buildRegex allows you to create and configure your own regex patterns with options for case-insensitivity, multiline matching, and more. (Further documentation on buildRegex API and options will be provided in upcoming updates if this feature is implemented). (Currently, direct regex patterns can be used as shown in the ZIP code example in previous sections.)

    import { createSchema } from 'forgeform';
     
    interface CustomRegexFormData {
      productCode?: string;
    }
     
    const customRegexSchema = createSchema<CustomRegexFormData>({
      fields: {
        productCode: {
          type: 'string',
          required: true,
          pattern: /^[A-Z]{3}-\d{4}$/, // Example: 3 uppercase letters, hyphen, 4 digits (e.g., ABC-1234)
          requiredErrorMessage: 'Product code is required',
          patternErrorMessage: 'Invalid product code format. Should be like ABC-1234',
        },
      },
    });

    In this example, a custom regex pattern ^[A-Z]{3}-\d{4}$ is directly used to validate the productCode field, enforcing a specific format.

On this page