Skip to content

Custom Validators

Extend the built-in validation with custom rules using registerValidator().

Registering a Validator

typescript
import { registerValidator } from '@anhanga/react' // or '@anhanga/vue' or '@anhanga/svelte'

registerValidator('cpf', (value, params, translate) => {
  if (!value) return null
  return isValidCPF(String(value)) ? null : translate?.('validation.cpf') ?? 'Invalid CPF'
})

Validator Signature

typescript
type ValidatorFn = (
  value: unknown,
  params: Record<string, unknown> | undefined,
  translate?: TranslateContract,
) => string | null
ParameterDescription
valueThe field's current value
paramsOptional parameters from the validation rule
translateTranslation function for error messages

Return null if valid, or a string error message if invalid.

Examples

Email Domain Validator

typescript
registerValidator('emailDomain', (value, params, translate) => {
  if (!value) return null
  const domain = params?.domain as string
  if (!String(value).endsWith(`@${domain}`)) {
    return translate?.('validation.emailDomain') ?? `Must be a @${domain} email`
  }
  return null
})

Async-Compatible Validator

Validators are synchronous. For async validation, handle it in event handlers or action handlers instead:

typescript
const events = PersonSchema.events({
  email: {
    async blur({ state, schema }) {
      const exists = await checkEmailExists(state.email)
      if (exists) {
        schema.email.state = 'error'
      }
    },
  },
})

Built-in Validators

These validators are available out of the box:

NameDescriptionParams
requiredNon-empty value
minLengthMinimum string length{ min: number }
maxLengthMaximum string length{ max: number }
minMinimum numeric value{ min: number }
maxMaximum numeric value{ max: number }
minDateMinimum date bound{ min: string }
maxDateMaximum date bound{ max: string }
patternRegex match{ pattern: string, message?: string }

Released under the MIT License.