VVibeFlui

Registry Validators

Validators add custom field validation.

Built-in declarative validation runs first. If a built-in rule fails, the custom validator is not needed for that field. If built-in rules pass and the field has a validator key, VibeFlui looks up that key in registry.validators.

Schema usage

schemas/users/user-form.schema.ts

TS
export const userFormSchema = {
  version: "1.0.0",
  resource: "users",
  form: {
    fields: [
      {
        name: "email",
        label: "Email",
        type: "email",
        required: true,
        validator: "users.email"
      },
      {
        name: "username",
        label: "Username",
        type: "text",
        minLength: 3,
        validator: "users.username"
      }
    ]
  },
  registry: {
    validators: ["users.email", "users.username"]
  }
} as const;

Runtime registry

lib/vibeflui/registry.ts

TS
import { createRegistry } from "@vibeflui/core";

export const registry = createRegistry({
  validators: {
    "users.email": async (value) => {
      const email = String(value ?? "");
      return email.endsWith("@example.com") ? undefined : "Use an example.com email address.";
    },
    "users.username": (value) => {
      const username = String(value ?? "");
      return /^[a-z0-9_]+$/.test(username) ? undefined : "Use lowercase letters, numbers, or underscores.";
    }
  }
});

Return value

Validators return:

  • undefined when the value is valid.
  • A string error message when the value is invalid.

lib/vibeflui/validation-results.ts

TS
const valid = undefined;
const invalid = "Enter a valid email address.";

Validator context

Validators receive the field value and runtime component context.

lib/vibeflui/registry.ts

TS
export const registry = createRegistry({
  validators: {
    "users.confirmEmail": (value, context) => {
      return value === context.values?.email ? undefined : "Email confirmation does not match.";
    }
  }
});

Built-in validation vs custom validation

Use built-in rules for simple constraints:

schemas/users/user-fields.ts

TS
{
  name: "age",
  type: "number",
  min: 18,
  max: 120
}

Use registry validators for product-specific rules:

schemas/users/user-fields.ts

TS
{
  name: "email",
  type: "email",
  validator: "users.companyEmail"
}

Backend responsibility

Client validators are for user experience. The backend must still validate every submitted value.