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 does not currently support 3rd-party libraries like Yup, Zod or Joi. Check introduction to understand if it is planned.
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 withfields
is checked for nullish values or empty strings.
- This is a list of fields by name that you consider required. By default, there is an error message in English -
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
There are built-in transformations that happen based on the input.type
React Browser Forms finds in DOM.
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.