Skip to main content

Validation

Formitiva provides a flexible validation system supporting:

  • Built-in (declarative) validation
  • Field-level custom validation
  • Form-level validation
  • Synchronous and asynchronous handlers
  • Configurable validation timing

Built-in Validation

Built-in validators are defined declaratively in the field schema.
They work out-of-the-box in the renderer and are supported by the visual builder.

Supported Rules

Required

Property required indicate the value is required and can't be empty. Default is false.

{
"required": true
}

Numeric Fields

PropertyDescription
minMinimum value
maxMaximum value
minInclusiveInclude min in validation (default: true)
maxInclusiveInclude max in validation (default: true)
stepStep increment (for steppers)

Text / Multiline

PropertyDescription
minLengthMinimum character length
maxLengthMaximum character length

Arrays (int & float)

PropertyDescription
minCountMinimum number of items
maxCountMaximum number of items

Date

PropertyDescription
minDateEarliest allowed date
maxDateLatest allowed date

Pattern (Regex)

PropertyDescription
patternRegex string
patternErrorMessageCustom validation message
  • Example:
{
"name": "zip",
"type": "text",
"pattern": "^[0-9]{5}$",
"patternErrorMessage": "Please enter a 5-digit ZIP code"
}

Built-in Validation Notes

  • Built-in validators run before custom validators.
  • When built-in validation fail, error returned and custom validation is skipped.

Field Validation Mode

The fieldValidationMode prop controls when field validation runs.

Modes

ModeDescription
"onEdit"Validate while editing. Errors appear immediately.
"onBlur"Validate when edit lose focus.
"onSubmission"Validate only on submit. Submission is blocked if invalid.
"realTime"Deprecated. Same as "onEdit".

Example

// Validate during editing
<Formitiva
definitionData={definition}
instance={instance}
fieldValidationMode="onEdit"
/>

// Validate when input lose focus
// A component may contains several inputs, when one of input lose focus, validation will be triggered
<Formitiva
definitionData={definition}
instance={instance}
fieldValidationMode="onBlur"
/>

// Validate only on form submit
<Formitiva
definitionData={definition}
instance={instance}
fieldValidationMode="onSubmission"
/>

Field-Level Validation

Field-level validators validate a single field.

Use cases:

  • Format validation
  • Value constraints

Registration

  1. Register a handler in your application.
  2. Reference it in the field definition.

Handler Signature

export type FieldCustomValidationHandler = (
fieldName: string,
value: FieldValueType | unknown,
t: TranslationFunction,
) => string | undefined;
  • Return Value
    • Return a string when a validation error occurs.
      The string represents the error message (preferably localized using t).
    • Return undefined when validation succeeds (no error).

registerFieldCustomValidationHandler signature

export function registerFieldCustomValidationHandler(
category: string, // Category name. Normally definition name, also can be `math`, `business`, ...
name: string,
fn: FieldCustomValidationHandler
): void
  • Parameters
    • category : category name to group same functionality handlers. Normally it is definition name, can also be other names: math, business, ...
    • name : handler name
    • fn : field custom validation handler(function)

Example

registerFieldCustomValidationHandler('math', 'evenNumber', (fieldName, value, t) => {
const number = Number(value);
if (Number.isFinite(number) || value % 2 !== 0) {
return t('Value must be an even number');
}
return undefined;
});

Field definition:

The optional validationHandlerName of each property specifies the registered validation handler

validationHandlerName: string | [string, string]
  • Note:
    • string : handler name, category name is default to definition name
    • [string, string] : first value is category name and second value is handler name
{
"name": "evenNumber",
"type": "int",
"validationHandlerName": ["math", "evenNumber"]
}

Field-Level Notes

  • Typically triggered on blur or change.
  • Prefer returning localized message keys via t().
  • For performance consideration, field level validation is synchronous process, if a field needs asynchronous validation, use form level validation to check it.

Field Type Validation

When you define a new type of component, you can define a type validation for this component.

Handler signature

export type FieldTypeValidationHandler = (
field: DefinitionPropertyField,
input: FieldValueType,
t: TranslationFunction,
) => string | undefined;
  • Paramter
    • field : field definition
    • input : the field input value for validation
    • t : translation function
  • Return
    • Return a string when a validation error occurs.
      The string represents the error message (preferably localized using t).
    • Return undefined when validation succeeds (no error).

Registration

export function registerFieldTypeValidationHandler(
name: string,
fn: FieldTypeValidationHandler
): void
  • Parameters
    • name : the new component type name, used to specify the type property in definition
    • fn : type validation handler

Example

Please check custom component document for the example Type Validation

Form-Level Validation

Form-level validators validate multiple fields together and support asynchronous validation.

Use cases:

  • Cross-field validation (e.g., confirm password, compare values,...)
  • Combined constraints
  • Server-side validation requiring full form context

Registration

  1. Register a form validation handler.
  2. Reference it at the form root using validationHandlerName.

Handler signature

export type FormValidationHandler = (
valuesMap: Record<string, FieldValueType | unknown>,
t: TranslationFunction,
) => string[] | Promise<string[] | undefined> | undefined;
  • Parameters
    • valuesMap: map of property name to value
    • t : translation function, use for localize error messages
  • Returns
    string[] : error messsages when there are errors undefined: validation success

Registration signamture

export function registerFormValidationHandler(
name: string,
fn: FormValidationHandler
): void
  • Parameter
    • name : form validation handler name
    • fn : form validation handler
  • Return: void

Example

  • Define the Validation Function

    const uniqueEmailCheck = async (
    valuesMap: Record<string, any>,
    t: TranslationFunction
    ) => {
    const errors: Record<string, string> = {};

    if (valuesMap.email && !(await api.isEmailUnique(valuesMap.email))) {
    errors.Add(t('Email already in use'));
    }

    return Object.keys(errors).length ? { errors } : undefined;
    };
  • Register the Validation Function

    registerFormValidationHandler('uniqueEmailCheck', uniqueEmailCheck);
  • Form definition: Specify the uniqueEmailCheck in defintion root validationHandlerName

    {
    "name": "signup",
    "displayName": "Sign up",
    "validationHandlerName": "uniqueEmailCheck",
    "properties": [/* ... */]
    }

Form-Level Notes

  • Runs on submit by default.
  • Can be triggered earlier via custom hooks.
  • Return field-mapped errors for better UI integration.
  • Use t() for localization.

Sync/Async Validation

Field-level handler is synchronous and Form-level handlers can be asynchronous.

Best Practices

  • For performance consideration, field validation process simple single field validation.
  • Put time consuming and asynchronous validation in form validation

Error Messages & Localization

Validation messages should be:

  • Consistent
  • Localizable
  • Centralized

Localiztion dictionary

In formitiva, dictionary is used for translate error messages.

  • Localization can be specify a dictionary file in defintion with property localization
  • The dictionary file is put in public/locales/{lang}

Recommendations

  • Prefer message keys resolved via t().
  • Use schema-level message properties (e.g., patternErrorMessage).

Validation Execution Order

  1. Built-in field validators
  2. Custom field-level validators
  3. Form-level validators (typically on submit)