react-phone-number-input: Can't figure out how to use this with Formik field component

I’m using Formik and trying to use this package, but Formik can’t see the value of the input and thus doesn’t validate or submit the form.

Here’s the PhonInputField component that I’m using …

import PhoneInput from "react-phone-number-input";

const PhoneInputField = ({
    field,
    form
}) => {
    return (
        <div className="input-field">
            <PhoneInput
                placeholder="Enter phone number"
                name={field.name}
                value={field.value}
                onChange={field.onChange}
                onBlur={field.onBlur}
            />
        </div>
    );
};

export default PhoneInputField;

And here’s how I’m using it in Formik …

<Formik
    initialValues={initialValues}
    validationSchema={signInSchema}
    onSubmit={handleFormSubmit}
>
    {({
        isValid,
        isSubmitting,
        handleChange,
        handleBlur
    }) => (
        <Form>


                <Field
                    type="tel"
                    name="phone_number"
                    component={PhoneInputField}
                />

            <div className="cta">
                <button
                    type="submit"
                    disabled={!isValid || isSubmitting}
                    className="btn btn-primary big"
                >Submit</button>
            </div>
        </Form>
    )}
</Formik>

What am I doing wrong here?

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 26 (10 by maintainers)

Most upvoted comments

If it helps, here is my phoneinput/formik control

import React, { useState } from 'react';
import PhoneInput from 'react-phone-number-input';
import PropTypes from 'prop-types';
import 'react-phone-number-input/style.css';
import { getIn } from 'formik';


const PhoneInputField = (props) => {
  const {
    className,
    field: { name, value },
    form: {
      errors, handleBlur, setFieldValue, touched,
    },
    form,
    label,
    country,
    onChange,
    disabled,
  } = props;

  const [isFocused, setFocused] = useState(false);
  const isError = getIn(touched, name) && getIn(errors, name);
  const errorStyle = isError ? 'error' : '';
  const filledStyle = (isFocused || value) ? 'filled' : '';
  const disabledStyle = disabled ? 'disabled' : '';

  const handleInputBlur = (e) => {
    setFocused(false);
    handleBlur(e);
  };

  const handleInputFocus = () => setFocused(true);

  const onValueChange = (phoneNumber) => {
    setFieldValue(name, phoneNumber);

    if (onChange !== null) {
      onChange(phoneNumber);
    }
  };

  return (
    <div className={`${className} ${errorStyle} ${filledStyle} ${disabledStyle} text-input-group`}>
      <PhoneInput
        placeholder="Enter phone number"
        name={name}
        value={value}
        onChange={onValueChange}
        country={country}
      />
      <label className="transition ml-10" htmlFor={name}>
        {label}
      </label>
      <div className="flex h-5 items-end text-red-100 text-xs">
        {isError && getIn(errors, name)}
      </div>
    </div>
  );
};

PhoneInputField.propTypes = {
  className: PropTypes.string,
  form: PropTypes.any.isRequired,
  field: PropTypes.any.isRequired,
  onChange: PropTypes.func,
  label: PropTypes.string,
  country: PropTypes.string,
  disabled: PropTypes.bool,
};

PhoneInputField.defaultProps = {
  className: '',
  label: '',
  onChange: null,
  country: 'AU',
  disabled: false,
};

export default PhoneInputField;

In case if anyone needs help this is my current implementation. Below approach works with both onChange and onBlur events and doesn’t throw error when string is given in field (disabled). Thanks to above replies:

import "react-phone-number-input/style.css";
import PhoneInput from "react-phone-number-input";

const initialValues = {
    phoneNumber: "",
};

const validate = (values) => {
    let errors = {};
    if (!values.phoneNumber) {
      errors.phoneNumber = "⋆Required";
    }
    return errors;
  };

const onSubmit = (values, onSubmitProps) => {....}

  const formik = useFormik({
    initialValues,
    onSubmit,
    validate,
  });

<PhoneInput
          className='anonymous'
          placeholder='Phone Number'
          name='phoneNumber'
          value={formik.values.phoneNumber}
          onChange={e => formik.setFieldValue("phoneNumber", e)}
          onBlur={formik.handleBlur("phoneNumber")}
        />
        {formik.touched.phoneNumber && formik.errors.phoneNumber ? (
          <div
            className='text-danger text-right'
            style={{ marginBottom: "-13px", fontSize: "12px" }}
          >
            {formik.errors.phoneNumber}
          </div>
        ) : null}

@catamphetamine please find a working implementation for future reference. https://codesandbox.io/s/formik-react-phone-number-input-p5jvs

I have modified @AndrewStratigos 's version. This version works right with Formik’s onBlur, allowing you to validate the field on blur.

import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import PhoneInput from 'react-phone-input-2';
import block from 'bem-css-modules';
import classNames from 'classnames';
import { createRandomIdentificator } from '../../../helpers/commonHelpers';
import styles from './styles.module.scss';

const b = block(styles);

export default function MaskedInput(props) {
    const {
        handleChange,
        handleBlur,
        className,
        type,
        placeholder,
        name,
        ...restProps
    } = props;

    const inputClassPostfix = createRandomIdentificator();

    useEffect(() => {
        document.querySelector(`.phone-input-${inputClassPostfix}`).setAttribute('name', name);
    });

    const onValueChange = (phoneNumber, country, e) => {
        handleChange(e);
    };

    return (
        <PhoneInput
            {...restProps}
            country="ru"
            preferredCountries={['ru']}
            value={null}
            placeholder={placeholder}
            containerClass={b('container')}
            inputClass={classNames(b('input'), `phone-input-${inputClassPostfix}`)}
            buttonClass={b('button')}
            onChange={onValueChange}
            onBlur={handleBlur}
            name={name}
        />
    );
}

MaskedInput.defaultProps = {
    type: 'text',
    placeholder: '',
    name: '',
    className: '',
};

MaskedInput.propTypes = {
    name: PropTypes.string,
    placeholder: PropTypes.string,
    type: PropTypes.string,
    className: PropTypes.string,
    handleBlur: PropTypes.func.isRequired,
    handleChange: PropTypes.func.isRequired,
};

@AndrewStratigos That did actually work, Thanks a lot man. The trick in your code was this part …

const onValueChange = phoneNumber => {
        setFieldValue(name, phoneNumber);

        if (onChange !== null) {
            onChange(phoneNumber);
        }
    };

Again, thanks a bunch 👍

In case if anyone needs help this is my current implementation. Below approach works with both onChange and onBlur events and doesn’t throw error when string is given in field (disabled). Thanks to above replies:

import "react-phone-number-input/style.css";
import PhoneInput from "react-phone-number-input";

const initialValues = {
    phoneNumber: "",
};

const validate = (values) => {
    let errors = {};
    if (!values.phoneNumber) {
      errors.phoneNumber = "⋆Required";
    }
    return errors;
  };

const onSubmit = (values, onSubmitProps) => {....}

  const formik = useFormik({
    initialValues,
    onSubmit,
    validate,
  });

<PhoneInput
          className='anonymous'
          placeholder='Phone Number'
          name='phoneNumber'
          value={formik.values.phoneNumber}
          onChange={e => formik.setFieldValue("phoneNumber", e)}
          onBlur={formik.handleBlur("phoneNumber")}
        />
        {formik.touched.phoneNumber && formik.errors.phoneNumber ? (
          <div
            className='text-danger text-right'
            style={{ marginBottom: "-13px", fontSize: "12px" }}
          >
            {formik.errors.phoneNumber}
          </div>
        ) : null}

Thank you so much. This helped me. Apparently, the trick was the formik.setFieldValue method

Thanks a lot MidhaTahir Now I have finally passed the issue from react-phone-input-2😊😊

@boriswinner Ok, what are the main issues when using this library with formik “out of the box”?

  • Issue 1
  • Issue 2 …

Perhaps we could add a section in the readme on using this library with formik or other libraries.

@jdmg94 So what does the ultimate Formik component look like then? Where does formik.handleChange go in this code?

import React, { useCallback } from 'react'
import PropTypes from 'prop-types'
import PhoneInput from 'react-phone-number-input`

function FormikPhoneInput(ref, { name, onChange, formik, ...rest }) {
  const onChange_ = useCallback(value => onChange(value || ''), [onChange])
  return (
    <PhoneInput
      {...rest}
      ref={ref}
      name={name}
      onChange={onChange_}/>
  )
}

FormikPhoneInput = React.forwardRef(FormikPhoneInput)

FormikPhoneInput.propTypes = {
  name: PropTypes.string.isRequired,
  onChange: PropTypes.func.isRequired,
  formik: PropTypes.shape({
    handleChange: PropTypes.func.isRequired,
    handleBlur: PropTypes.func.isRequired
  }).isRequired
}

export default FormikPhoneInput

Also, in v3.x of this library, onBlur no longer sets event.target.value, so I removed onBlur from this code. If you think it’s still required then you could add it.

remove onChange_ and just call in your jsx onChange={formik.handleChange(name)} same with onBlur if you need validation on blur

I may be late to the party but for anyone else here having issues with their onChange handler, remember this also comes with a curried option, in a regular web input formik can take the name attribute from the target it receives in the change handler, React-native generally doesn’t provide a synthetic event (it does but its different) most people tend to use the onChangeText property instead so formik needs other queues to know how to update the form’s state, consider the following:

instead of calling the change (or blur) handlers like we do on web: onChange={formik.handleChange}

you call it with the attribute name: onChange={formik.handleChange('phoneNumber')} this also works for the blur handler onBlur={formik.handleBlur('phoneNumber')} also make sure you send the change values as string or formik won’t accept it, it sometimes is a pain in the ass to work forms on RN

Perhaps the reason could be formik expecting onChange(event) instead of onChange(value). See if something like onChange={value => field.onChange({ target: { value } })} would work.