'Formik - Render ErrorMessage automatically

I have the following code which you can find here:

https://stackblitz.com/edit/react-d2fadr?file=src%2FApp.js

import { ErrorMessage, Field, Form, Formik } from 'formik';
import React from 'react';
import { Button } from 'react-bootstrap';
import * as Yup from 'yup';

let fieldName = 'hexColor';

const TextInput = ({ field, value, placeholder, handleChange }) => {
  value = (field && field.value) || value || '';
  placeholder = placeholder || '';
  return (
    <input
      type="text"
      placeholder={placeholder}
      onChange={(e) => handleChange(e.target.value)}
      value={value}
    />
  );
};

export default () => {
  const onSubmit = (values, { setSubmitting }) => {
    console.log(values);
    setSubmitting(false);
  };

  return (
    <Formik
      initialValues={{ [fieldName]: 'ff0000' }}
      validationSchema={Yup.object({
        hexColor: Yup.string().test(
          fieldName,
          'The Hex Color is Wrong.',
          (value) => {
            return /^[0-9a-f]{6}$/.test(value);
          }
        ),
      })}
      onSubmit={onSubmit}
      enableReinitialize
    >
      {(formik) => {
        const handleChange = (value) => {
          value = value.replace(/[^0-9a-f]/g, '');
          formik.setFieldValue(fieldName, value);
        };
        return (
          <Form>
            <div>
              <Field
                component={TextInput}
                name={fieldName}
                placeholder="Hex Color"
                handleChange={handleChange}
              />&nbsp;
              <ErrorMessage name={fieldName} />
            </div>
            <Button
              type="submit"
              disabled={!formik.isValid || formik.isSubmitting}
            >
              Submit
            </Button>
          </Form>
        );
      }}
    </Formik>
  );
};

I want to know if is it any way to render the ErrorMessage element automatically?

The error message should be shown somewhere around the input text.

If you know how, you can fork the StackBlitz above with your suggestion.

Thanks!



Solution 1:[1]

Don't really know why ErroMessage is not rendering before you submit your form once but you can replace the line <ErrorMessage name={fieldName} /> by {formik.errors[fieldName]} to make it works

import { ErrorMessage, Field, Form, Formik } from 'formik';
import React from 'react';
import { Button } from 'react-bootstrap';
import * as Yup from 'yup';

let fieldName = 'hexColor';

const TextInput = ({ field, value, placeholder, handleChange }) => {
  value = (field && field.value) || value || '';
  placeholder = placeholder || '';
  return (
    <input
      type="text"
      placeholder={placeholder}
      onChange={(e) => handleChange(e.target.value)}
      value={value}
    />
  );
};

export default () => {
  const onSubmit = (values, { setSubmitting }) => {
    console.log(values);
    setSubmitting(false);
  };

  return (
    <Formik
      initialValues={{ [fieldName]: 'ff0000' }}
      validationSchema={Yup.object({
        hexColor: Yup.string().test(
          fieldName,
          'The Hex Color is Wrong.',
          (value) => {
            return /^[0-9a-f]{6}$/.test(value);
          }
        ),
      })}
      onSubmit={onSubmit}
      enableReinitialize
    >
      {(formik) => {
        const handleChange = (value) => {
          value = value.replace(/[^0-9a-f]/g, '');
          formik.setFieldValue(fieldName, value);
        };
        return (
          <Form>
            <div>
              <Field
                component={TextInput}
                name={fieldName}
                placeholder="Hex Color"
                handleChange={handleChange}
              />&nbsp;
              {formik.errors[fieldName]}
            </div>
            <Button
              type="submit"
              disabled={!formik.isValid || formik.isSubmitting}
            >
              Submit
            </Button>
          </Form>
        );
      }}
    </Formik>
  );
};

Solution 2:[2]

the issue is validation schema. When I changed 6

 return /^[0-9a-f]{6}$/.test(value);

to 3

 return /^[0-9a-f]{3}$/.test(value);

and submitted with the initial value, ErrorMessage component is rendered

enter image description here

Solution 3:[3]

To reach your goal, I changed your code as below:

  1. Since Formik's default component is Input, I deleted your TextInput component as there was nothing special in your component and handleChange function.
<Field name="hexColor" placeholder="Hex Color" onChange={(e) => handleChange(e.target.value)}/>
<ErrorMessage name="hexColor" />
  1. As in mentioned in this answer, I changed your submit button condition to determine whether the button is disabled or not:
<Button type="submit" disabled={Object.keys(errors).length}>
  Submit
</Button>

You can view my entire solution here.

Edit

If you want to keep your component, you should pass props as you might be missing something important, e.g. onChange,onBlur etc.

const TextInput = ({ field, ...props }) => {
  return (
    <input
      {...field} {...props}
      // ... your custom things
    />
  );
};

<Field
  component={TextInput}
  name={fieldName}
  placeholder="Hex Color"
  onChange={(e) => handleChange(e.target.value)}
/>

Solution 2

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Roy Christo
Solution 2 Yilmaz
Solution 3