resolver and validator

CreateForm and useForm support two validation mechanisms: a resolver and a validator. The resolver performs schema-based validation using zod, yup, or superstruct. The validator uses built-in rules such as required, checked, minLength, maxLength, RegExp, and custom. Both approaches can be used together or independently. Note: if both are used, resolver runs first — if resolver fails, validator won't run. This enables a layered approach: use schema validation for basic shape and types and use validator for more dynamic or complex checks.

validator and validate#

validator and validate may seem similar but differ in purpose and scope.

  • validate object: a per-field validation object (required, minLength, RegExp, ...).
  • validator object: a top-level map of validate objects for the whole form, keyed by field name.

In short, validator defines what to validate (a map of validate objects for the whole form), while validate defines how to validate a single field. This hierarchy enables systematic form validation and allows register to override per-field validators when needed.

required#

The required rule checks whether a field has a value. It accepts a boolean or an object like { required: boolean, message: string }. If only a boolean is provided, a default error message is used. Providing an object allows a custom message. Place required early in the validator array so subsequent rules run only when required passes.

minLength and maxLength#

minLength and maxLength validate string length. They accept a number or an object like { number: number, message: string }. Use minLength for minimum characters and maxLength for maximum characters.

checked#

checked validates whether checkbox-like inputs are selected. It accepts boolean or an object like { checked: boolean, message: string }. Use it for terms acceptance or required consent checkboxes.

RegExp and custom#

RegExp and custom accept arrays of validator objects, enabling multiple checks. RegExp validates patterns, custom accepts a function. If no message is provided, a default message is used. Sicilian evaluates validators sequentially and stops at the first failure.

custom's checkFn receives the field value and the full formState and returns a boolean: true indicates an error, false indicates success. For example, checkFn: (value, store) => value !== store.password checks password confirmation. Multiple validators can be provided as an array.

The strength of custom is enabling dynamic, external-data-driven validation. For instance, a backend-managed blocklist can be fetched and applied by a custom validator without changing frontend code when the blocklist updates.

validateOptions#

sicilian provides validateOptions to help write type-safe validate objects. While it may appear to return the provided object unchanged, in TypeScript it improves inference and IDE autocomplete by preserving accurate types for store and field values.

priority and order of validation#

There are two ways to provide validate: the validator option on CreateForm/useForm or the validate object passed to register. Both formats are the same, but register's validate overrides the form-level validator. The order of rules matters; validators run in declared order and stop on first failure.

The order of validations matters: the rules inside a validate object are evaluated in the declared order, and validation stops at the first failing rule. In the first example below, the minLength rule runs before required (so if minLength passes, required effectively does nothing). In the second example, required first checks for a value and minLength then checks its length. If a field's validation behaves unexpectedly, check the order of the rules for that field.

Guides - Getting Started with Sicilian | ilokesto - React Library Collection