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
| Property | Description |
|---|---|
min | Minimum value |
max | Maximum value |
minInclusive | Include min in validation (default: true) |
maxInclusive | Include max in validation (default: true) |
step | Step increment (for steppers) |
Text / Multiline
| Property | Description |
|---|---|
minLength | Minimum character length |
maxLength | Maximum character length |
Arrays (int & float)
| Property | Description |
|---|---|
minCount | Minimum number of items |
maxCount | Maximum number of items |
Date
| Property | Description |
|---|---|
minDate | Earliest allowed date |
maxDate | Latest allowed date |
Pattern (Regex)
| Property | Description |
|---|---|
pattern | Regex string |
patternErrorMessage | Custom 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
| Mode | Description |
|---|---|
"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
- Register a handler in your application.
- 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 usingt). - Return
undefinedwhen validation succeeds (no error).
- Return a string when a validation error occurs.
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 namefn: 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
blurorchange. - 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 definitioninput: the field input value for validationt: translation function
- Return
- Return a string when a validation error occurs.
The string represents the error message (preferably localized usingt). - Return
undefinedwhen validation succeeds (no error).
- Return a string when a validation error occurs.
Registration
export function registerFieldTypeValidationHandler(
name: string,
fn: FieldTypeValidationHandler
): void
- Parameters
name: the new component type name, used to specify the type property in definitionfn: 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
- Register a form validation handler.
- 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 valuet: translation function, use for localize error messages
- Returns
string[]: error messsages when there are errorsundefined: validation success
Registration signamture
export function registerFormValidationHandler(
name: string,
fn: FormValidationHandler
): void
- Parameter
name: form validation handler namefn: 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
uniqueEmailCheckin defintion rootvalidationHandlerName{
"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
- Built-in field validators
- Custom field-level validators
- Form-level validators (typically on submit)