Validation

Validate SimpleForm inputs with schemas or per-field rules.

Validation

To validate the form values, provide a validate function taking the record as input, and returning an object with error messages indexed by field. For instance:

const validateUserCreation = (values) => {
  const errors = {};
  if (!values.firstName) {
    errors.firstName = "The firstName is required";
  }
  if (!values.age) {
    // You can return translation keys
    errors.age = "ra.validation.required";
  } else if (values.age < 18) {
    // Or an object if the translation messages need parameters
    errors.age = {
      message: "ra.validation.minValue",
      args: { min: 18 },
    };
  }
  return errors;
};
 
export const UserCreate = () => (
  <Create>
    <SimpleForm validate={validateUserCreation}>
      <TextInput label="First Name" source="firstName" />
      <TextInput label="Age" source="age" />
    </SimpleForm>
  </Create>
);

Alternatively, you can specify a validate prop directly in <Input> components, taking either a function or an array of functions. Ra-core already bundles a few validator functions, that you can just require, and use as input-level validators:

  • required(message) if the field is mandatory,
  • minValue(min, message) to specify a minimum value for integers,
  • maxValue(max, message) to specify a maximum value for integers,
  • minLength(min, message) to specify a minimum length for strings,
  • maxLength(max, message) to specify a maximum length for strings,
  • number(message) to check that the input is a valid number,
  • email(message) to check that the input is a valid email address,
  • regex(pattern, message) to validate that the input matches a regex,
  • choices(list, message) to validate that the input is within a given list,
  • unique() to validate that the input is unique (see useUnique),

Example usage:

import {
  required,
  minLength,
  maxLength,
  minValue,
  maxValue,
  number,
  regex,
  email,
  choices,
} from "ra-core";
 
const validateFirstName = [required(), minLength(2), maxLength(15)];
const validateEmail = email();
const validateAge = [number(), minValue(18)];
const validateZipCode = regex(/^\d{5}$/, "Must be a valid Zip Code");
const validateGender = choices(
  ["m", "f", "nc"],
  "Please choose one of the values",
);
 
export const UserCreate = () => (
  <Create>
    <SimpleForm>
      <TextInput
        label="First Name"
        source="firstName"
        validate={validateFirstName}
      />
      <TextInput label="Email" source="email" validate={validateEmail} />
      <TextInput label="Age" source="age" validate={validateAge} />
      <TextInput label="Zip Code" source="zip" validate={validateZipCode} />
      <SelectInput
        label="Gender"
        source="gender"
        choices={[
          { id: "m", name: "Male" },
          { id: "f", name: "Female" },
          { id: "nc", name: "Prefer not say" },
        ]}
        validate={validateGender}
      />
    </SimpleForm>
  </Create>
);

You can also define your own validator functions. These functions should return undefined when there is no error, or an error string.

const required =
  (message = "Required") =>
  (value) =>
    value ? undefined : message;
const maxLength =
  (max, message = "Too short") =>
  (value) =>
    value && value.length > max ? message : undefined;
const number =
  (message = "Must be a number") =>
  (value) =>
    value && isNaN(Number(value)) ? message : undefined;
const minValue =
  (min, message = "Too small") =>
  (value) =>
    value && value < min ? message : undefined;
 
const ageValidation = (value, allValues) => {
  if (!value) {
    return "The age is required";
  }
  if (value < 18) {
    return "Must be over 18";
  }
  return undefined;
};
 
const validateFirstName = [required(), maxLength(15)];
const validateAge = [required(), number(), ageValidation];
 
export const UserCreate = () => (
  <Create>
    <SimpleForm>
      <TextInput
        label="First Name"
        source="firstName"
        validate={validateFirstName}
      />
      <TextInput label="Age" source="age" validate={validateAge} />
    </SimpleForm>
  </Create>
);

Input validation functions receive the current field value and the values of all fields of the current record. This allows for complex validation scenarios (e.g. validate that two passwords are the same).