reactjsmaterial-uiformikformik-material-ui

"mui-one-time-password-input" is not working with "formik"


I am working on a Next.js Project, and I have to use mui-one-time-password-input library for OTP input. and for form validation I am using formik.

Now, when I try to apply value and onChange properties to MuiOtpInput component; Somehow, it is not accepting any input I provide in that MuiOtpInput field.

const OtpForm = () => {
    const formik = useFormik({
        initialValues: {
            otp: null,
            submit: null
        },
        validationSchema: Yup.object({
            otp: Yup
                .string()
                .length(6, 'Must be a valid OTP')
                .required('OTP is required')
        })
    });

    return (
        <form>
            <MuiOtpInput
                TextFieldsProps={{
                    placeholder: '-'
                }}
                onComplete={formik.handleSubmit}
                onChange={formik.handleChange}
                value={formik.values.otp}
                length={OTP_LENGTH}
            />
        </form>
    );
};

This works though...

const OtpForm = () => {
    const [otp,setOtp] = useState('')

    return (
        <form>
            <MuiOtpInput
                TextFieldsProps={{
                    placeholder: '-'
                }}                
                onChange={(val) => setOtp(val)}
                value={otp}
                length={OTP_LENGTH}
            />
        </form>
    );
};

Solution

  • To make it work with Formik you have to use setFieldValue not handleChange

    Here is an example:

                <MuiOtpInput
                  value={values.otp}
                  onChange={(value) => {
                    const digitsOnly = value.replace(/\D/g, '');
                    setFieldValue('otp', digitsOnly);
                  }}
                  length={6}
                  autoFocus
                  TextFieldsProps={{
                    type: 'text',
                    inputProps: {
                      maxLength: 1,
                      inputMode: 'text',
                      pattern: '[0-9]*',
                    },
                    onKeyDown: handleKeyDown,
                  }}
                />
                {touched.otp && errors.otp && (
                  <Typography variant="body2" color="error" sx={{ mt: 2 }}>
                    {errors.otp}
                  </Typography>
                )}
    

    This way it should works!