Skip to content

Validation

Validation runs on Submit or Continue click. No validation on blur.

Built-in rules

All rules are optional. Combine them freely.

json
{
  "key": "password",
  "type": "password",
  "label": "Password",
  "validation": {
    "required": true,
    "minLength": 8,
    "minLengthMessage": "Password must be at least 8 characters",
    "pattern": "(?=.*[A-Z])(?=.*[0-9])",
    "patternMessage": "Must include a number and uppercase letter"
  }
}
RuleTypeWhat it checksDefault message
requiredboolean | stringNot empty (null, undefined, or "")"This field is required"
minLengthnumberString length >= value"Must be at least N characters"
maxLengthnumberString length <= value"Must be at most N characters"
minnumberNumber >= value"Must be at least N"
maxnumberNumber <= value"Must be at most N"
patternstringMatches regex"Invalid format"
matchFieldstringValue equals another field's value"Fields must match"
validatorstringCustom validator function returns null(your message)

Every rule has a ...Message field for custom error text. Pass required: "Please enter your name" and that string becomes the error message.

matchField

Useful for "confirm email" or "confirm password" fields. When either field changes, the match is re-evaluated.

json
[
  {
    "key": "email",
    "type": "email",
    "label": "Email",
    "validation": { "required": true }
  },
  {
    "key": "confirmEmail",
    "type": "email",
    "label": "Confirm email",
    "validation": {
      "required": true,
      "matchField": "email",
      "matchFieldMessage": "Email addresses must match"
    }
  }
]

Custom validators

For validation that can't be expressed in JSON (API checks, business rules), register a validator function:

vue
<script setup>
import { FormRenderer } from '@formhaus/vue';

function validateFormat(value, allValues) {
  if (!value) return null;
  return isValidFormat(value) ? null : 'Invalid format';
}
</script>

<template>
  <FormRenderer
    :definition="definition"
    :validators="{ checkFormat: validateFormat }"
    @submit="onSubmit"
  />
</template>
tsx
<FormRenderer
  definition={definition}
  validators={{ checkFormat: validateFormat }}
  onSubmit={handleSubmit}
/>

function validateFormat(value: unknown, allValues: Record<string, unknown>) {
  if (!value) return null;
  return isValidFormat(value as string) ? null : 'Invalid format';
}

Reference the validator by name in the definition:

json
{
  "key": "code",
  "type": "text",
  "label": "Code",
  "validation": { "validator": "checkFormat" }
}

When validation runs

  • On Submit/Continue click. All visible fields on the current step are validated.
  • Async step validation. If onStepValidate is provided, it runs after sync validation passes but before the step transition. See Async Step Validation.
  • Never on blur. No errors while the user is still typing.
  • Hidden fields are skipped. If a show condition hides a field, it's not validated.
  • Empty non-required fields are skipped. minLength, pattern, etc. only run on non-empty values.

Next steps