Search code examples
reactjsformsvalidationformikyup

I want to transform value in Yup but Formik is not returning the correct value


I have a value in a form (email) that I want to transform into lowercase. I have a transform in Yup that's working, but Formik does not show a lowercase value.

How do I make it so that, when I enter the email in uppercase, it gets converted to lowercase automatically?

Here is my code:

import React from "react";
import { render } from "react-dom";
import { Formik } from "formik";
import * as Yup from "yup";

import { DisplayFormikState } from "./helper";
import "./style.css";

const validationSchema = Yup.object({
  email: Yup.string()
    .transform(function (value, originalvalue) {
      return this.isType(value) && value !== null ? value.toLowerCase() : value;
    })
    .email()
    .required()
    .label("Email")
});

const App = () => (
  <div className="app">
    <Formik
      initialValues={{ name: "" }}
      onSubmit={() => {}}
      validationSchema={validationSchema}
    >
      {(props) => {
        const { handleBlur, handleChange, values, errors, touched } = props;
        return (
          <form onSubmit={props.handleSubmit}>
            <h1>Email Form</h1>

            <input
              type="email"
              name="email"
              onChange={handleChange}
              onBlur={handleBlur}
              value={values.email}
            />
            {errors.email && touched.email && errors.email}

            <button type="submit">Submit</button>

            <DisplayFormikState {...props} />
          </form>
        );
      }}
    </Formik>
  </div>
);

render(<App />, document.getElementById("root"));

Solution

  • Formik and Yup must have two separate duties:

    • Formik manages the form's state (values)
    • Yup performs validations and tells Formik whether the values are valid or not

    Yup will not set the values in your form.

    Remove the case conversion from the Yup transformation. Instead, simply set the value to lowercase and pass it to setFieldValue() before yup does the validation.

    
    const validationSchema = Yup.object({
      email: Yup.string()
        .email()
        .required()
        .label("Email")
    });
    
    const App = () => (
      <div className="app">
        <Formik
          initialValues={{ email: "" }}
          onSubmit={() => {}}
          validationSchema={validationSchema}
        >
          {(props) => {
            const { handleBlur, setFieldValue, values, errors, touched } = props;
            return (
              <form onSubmit={props.handleSubmit}>
                <h1>Email Form</h1>
    
                <input
                  type="email"
                  name="email"
                  onChange={(e)=>{
                    const value = e.target.value || "";
                    setFieldValue('email', value.toLowerCase());
                  }}
                  onBlur={handleBlur}
                  value={values.email}
                />
                {errors.email && touched.email && errors.email}
    
                <button type="submit">Submit</button>
    
                <DisplayFormikState {...props} />
              </form>
            );
          }}
        </Formik>
      </div>
    );
    
    render(<App />, document.getElementById("root"));
    
    

    Live Demo