Validation and transformation

React Browser Form provides a minimal, but powerful first class API for helping with validation and data and/or type transformations.

Validation

Validation in React Browser Form is done in the easiest meaningful way possible. We aimed to make it type-safe, intuitive and re-usable. Using validation like this you can end up with a small amount of code that is just as powerful as using complex schemas. The error you throw with ValidationError will be used as error message.

This is an example validation:

const validationSchema: ValidationSchema<Form> = {
  // Required fields
  required: { fields: ["firstName", "lastName"], message: "An optional custom message" },

  validators: {
    // Basic validation
    age: age => if (age < 18) throw new ValidationError("You must be at least 18 years old.");

    // Composed validation
    jobTitle: [validatorFunction, anotherValidatorFunction],

    // Access all form data
    phoneNumber: (phoneNumber, data) =>
      if (!phoneNumber && !data.email) throw new ValidationError("Phone number is required if no e-mail provided."),
  },
}

There are 2 optional keys on the validationSchema that you need to be aware of:

  • required
    • This is a list of fields by name that you consider required. By default, there is an error message in English - "This field is required.". Any field provided with fields is checked for nullish values or empty strings.
  • validators
    • This is where you can harness the power of React Browser Form's type safety. Validators accepts named keys that correspond to your schema and should be a function that receives 2 arguments - current field and all form data. The field's data has a type you provided to React Browser Form when initializing.
    • Type annotation for validator functions is (fieldData: Schema[Key], formState: Schema) => void;
    • You can also compose your validators by providing an array of functions instead of a single function.

Re-using validation schema

We provide a utility function exported from React Browser Form that allows you test your validation schema against any object at your own will.

import { validateFormData } from "react-browser-form/utils"

Now you can test any object against your validation schema with optionally throwing validation errors.

import { validateFormData } from "react-browser-form/utils"

const validationSchema: ValidationSchema<any> = {
  required: { fields: ["firstName"] },
  validators: {
    nickname: nickname => {
      if (nickname.length < 8) throw new ValidationError(TEST_VALIDATION_ERR_MESSAGE);
    },
  },
};

const formDataToValidate = {
  firstName: "",
  nickname: "Joe",
};

// Testing without errors
const { hasErrors, errors } = validateFormData(formDataToValidate, validationSchema);

// Testing with errors
try {
  validateFormData(
    formDataToValidate,
    validationSchema,
    { shouldThrow: true },
  );
} catch (error) {
  // Use the following line to re-throw errors not coming from validation
  if (!(error instanceof ValidationError)) throw error;
}

Transformation

When using input types that correspons to your schema, like type="number", automatic transformation take place. You can prevent this by passing disableDefaultTransformation: true to the transformation schema. To see this in action, see Automatic value types example.

const transformationSchema: TransformationSchema<Form> = {
  // Optionally disable default transformation based on input.type
  disableDefaultTransformation: true,

  // Transform fields manually by name
  fields: {
    // Primitive type shorthands
    authorName: "string",
    authorAge: "number",

    // Type transformation
    authorBirthDate: value => new Date(Number(value)),

    // Value transformation
    authorUsername: value => String(value).toLowerCase().replaceAll(/[^a-z]/g, ""),
  },
}

You can provide your own transformations using the fields object on transformation schema. Here you can use shorthands (string "number" | "string" | "boolean") or a custom function with annotation (fieldData: unknown, formState?: Schema) => Schema[Key];, that takes in a field value and returns your new, transformed value.

You can easily transform just the types of the values or even mutate and change the data that is stored in form data. See Value transformation example to get an idea how it works.