Validation Guide

React Cool Form supports a wide range of synchronous and asynchronous validation strategies for built-in, form-level, and field-level validation to cover all the cases that you need.

Built-in Validation#

We support HTML form validation out of the box, a quick and easy way for form validation.

Edit RCF - Built-in validation

import { useForm } from "react-cool-form";
const App = () => {
const { form } = useForm({
defaultValues: { username: "", email: "", password: "" },
onSubmit: (values) => console.log("onSubmit: ", values),
onError: (errors) => console.log("onError: ", errors),
});
return (
<form ref={form} noValidate>
<input name="username" placeholder="Username" required />
<input name="email" type="email" placeholder="Email" required />
<input
name="password"
type="password"
placeholder="Password"
required
minLength={6}
/>
<input type="submit" />
</form>
);
};

Some validation attributes such as minLength, maxLength, min, and max are designed to validate a field once it has been edited by the user. If your validation relies on the related methods, use the pattern attribute or custom validation instead.

<input name="password" required pattern=".{6,}" /> // 6 characters minimum

Form-level Validation#

It provides a convenient way to access the complete values of the form (a.k.a formState.values), which is useful to validate dependent fields at the same time.

๐Ÿ’ก Please ensure the shape of the errors matches the shape of form's values. If you're dealing with complex form data, we've provided a set of utility functions to help you get shit done ๐Ÿ’ฉ.

Edit RCF - Form-level validation

import { useForm } from "react-cool-form";
// Synchronous validation
const validate = (values, actions) => {
const errors = {};
if (!values.email.length) {
errors.email = "Required";
} else if (!/^[A-Z0-9._-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = "Invalid email address";
}
// ...
return errors;
};
// Asynchronous validation
const validate = async (values, actions) => {
const errors = {};
const hasUser = await validateOnServer(values.username);
if (!hasUser) errors.username = "User doesn't exist";
// ...
return errors;
};
const App = () => {
const { form } = useForm({
defaultValues: { username: "", email: "" },
validate,
onSubmit: (values) => console.log("onSubmit: ", values),
onError: (errors) => console.log("onError: ", errors),
});
return (
<form ref={form} noValidate>
<input name="username" placeholder="Name" />
<input name="email" type="email" placeholder="Email" />
<input type="submit" />
</form>
);
};

In addition to write your own logic, it's also possible to use a 3rd-party library such as Yup, Joi, and many others with form-level validation. Let's take a look at the following example:

Edit RCF - Schema validation

import { useForm, set } from "react-cool-form";
import * as yup from "yup";
const schema = yup.object().shape({
username: yup.string().required(),
email: yup.string().email().required(),
password: yup.string().required().min(6),
});
const validate = async (values) => {
let errors = {};
try {
await schema.validate(values, { abortEarly: false });
} catch (yupErrors) {
// Convert the yup errors to field errors
// Use the "set" helper to assign properties for both "shallow" and "deep" (nested fields) object
yupErrors.inner.forEach(({ path, message }) => set(errors, path, message));
}
return errors;
};
const App = () => {
const { form } = useForm({
defaultValues: { username: "", email: "", password: "" },
validate,
onSubmit: (values) => console.log("onSubmit: ", values),
onError: (errors) => console.log("onError: ", errors),
});
return (
<form ref={form} noValidate>
<input name="username" placeholder="Username" />
<input name="email" type="email" placeholder="Email" />
<input name="password" type="password" placeholder="Password" />
<input type="submit" />
</form>
);
};

Field-level Validation#

Coming soon...

When Does Validation Run?#

By default, React Cool Form runs the above validation methods as below, you can tell React Cool Form when to run validation by the validateOnChange and/or validateOnBlur depends on your needs.

Event/methodTiming
onChangeWhenever the value of a field has been changed.
setFieldValueWhenever the value of a field has been set.
setValuesWhenever the values of the formState has been set.
onBlurWhenever a field has been touched. If a validation method has been run by the onChange event, it won't be run again.
onSubmitWhenever a submission attempt is made.
submitWhenever a submission attempt is made manually.
validateFieldManually run field-level validation.
validateFormManually run form-level validation.

Manually Triggering Validation#

Coming soon...

Displaying Error Messages#

Coming soon...