Skip to content

Validation

Vorm offers a powerful and extensible validation system supporting both built-in and custom rules. Each field in your schema can define one or more validation rules that are evaluated automatically based on your validation mode (e.g., onBlur, onInput, or on submit).

Basic Usage

Validation is defined per field using the validation property in the schema:

ts
{
  name: "email",
  type: "email",
  label: "E-Mail",
  validation: [
    { rule: "required" },
    { rule: "email" }
  ]
}

You can also define a custom error message:

ts
{
  name: "password",
  label: "Password",
  type: "password",
  validation: [
    { rule: "required", message: "Password is required" }
  ]
}

Built-in Rules

RuleDescription
requiredField must not be empty
emailMust be a valid email address
minMinimum numeric or string length (use with value)
maxMaximum numeric or string length (use with value)
betweenValue must be between min and max (use with min and max)
matchFieldMust match another field (e.g., confirm password)
stepValue must align to a given step (e.g., for numbers like 0.5)
integerMust be an integer
urlMust be a valid URL
alphaMust contain only alphabetic characters

Custom Functions

You can also define your own validator as a function:

ts
{
  name: "age",
  label: "Age",
  type: "number",
  validation: [
    {
      rule: (value: string): string | null => value.length >= 3 ? null : "Custom maxLength validator"
    }
  ]
}

The function can return:

  • null → valid
  • a string → interpreted as the error message
  • a ValidationResult → interpreted as the error message

ValidationResult

ts
export interface ValidationResult {
  message: string;
  params?: (string | number)[];
}

Async Validation

Async functions are supported out of the box:

ts
{
  name: "username",
  validation: [
    {
      rule: async (val) => {
        const taken = await api.checkUsername(val);
        return taken ? "Already taken" : null;
      }
    }
  ]
}

✅ Vorm automatically detects async rules and handles them just like sync ones — no configuration needed.

Affects: Reactive Error Mirroring

Validation rules can define an affects property to mirror their validation result onto other fields. This is especially useful for matching fields like email confirmation or cross-field conditions.

ts
{
  name: "confirmEmail",
  type: "email",
  validation: [
    {
      rule: "matchField",
      args: { field: "email" },
      affects: "email"
    }
  ]
},
{
  name: "email",
  type: "email"
}

If confirmEmail is invalid (e.g. does not match email), the same error will also be displayed on the email field.

You can also affect multiple fields:

ts
{
  rule: "myRule",
  validate: (value, formData) => true,
  affects: ["fieldA", "fieldB"]
}

✅ Affects does not revalidate other fields. Instead, it propagates the same error message to the specified fields if the current rule fails.

Controlling Validation Flow

You can control when a field is validated using validationMode, set globally or per field:

  • onBlur (default)
  • onInput
  • onSubmit

Set globally with:

ts
const { setValidationMode } = useVorm(schema, { validationMode: "onBlur" });

Or per field (inside the schema):

ts
{
  name: "email",
  label: "E-Mail-Adresse",
  type: "email",
  validationMode: "onInput",
  validation: [
    { rule: "required" },
    { rule: "email" }
  ]
}

Validation is core to Vorm’s architecture. Every rule is tracked, can be programmatically triggered, and integrates seamlessly with error display, repeater logic, and slot behavior.

MIT Licensed