Errors are a necessary part of all forms. Form requirements can range from very simple, to very complex. They range from simpler synchronous validations, to also including asynchronous validation. Formik
has first class support for both synchronous and asynchronous validation. The basic form of this is the validate
function. It can be a sync or async function.
The way that Formik
handles errors is that the returned error structure should map an error message to same structure as your values. In our case we have a single level object with a firstName
key. So if our value below is set like this, then our error should map accordingly.
{ firstName: '' } { firstName: 'Erorr message', }
It doesn't matter how you check for errors in this function it just matters that the structure is returned, or if valid that an empty object is returned.
So here we check if firstName
is empty and if it is we set an error message.
<Formik initialValues={{ firstName: "", }} onSubmit={handleSubmit} validate={(values) => { let errors = {}; if (!values.firstName) { errors.firstName = "Required"; } return errors; }} ></Formik>
Here we will control how an error gets rendered. The useField
hook and Field
both supply a meta
object. The meta
object is meta information about the specific field that's being rendered.
So in our case it's referencing meta information about our firstName
field. A field might be in an erroneous state but we don't want to bombard the user with the error message before they've even touched the field.
When a user interacts with a field, then triggers an onBlur
the touched
value is set to true. This allows us to now display an error message once we know it's been touched
and also that an error
exists.
const MySpecialField = () => { const [field, meta] = useField("firstName"); return ( <div> <input {...field} className="border-2" /> {meta.touched && meta.error && <div>{meta.error}</div>} </div> ); };
Generally the standard for displaying an error is that you need to have touched the field, and that an error exists. Formik ships with the ErrorMessage
helper component.
import { ErrorMessage } from "formik";
You supply it with a name
. When that fields contains an error and the field has been touched. Then it will display whatever the error text is. You can supply any component you'd like and it will pass the error text as a child.
<div> <Field name="firstName" className="border-2" /> <ErrorMessage name="firstName" component="div" /> </div>
One thing to realize is that if the user submits all fields are set to the touched
status. So even if the user didn't trigger an onBlur
on the firstName
field. Then opted to click the Submit
button, the error messages will pop up.
This is generally what you want but if this isn't than you may need to handle how errors are displayed in your form and not use the ErrorMessage
component.
import React from "react"; import { Formik, Form, Field, useField, ErrorMessage } from "formik"; const MySpecialField = () => { const [field, meta] = useField("firstName"); return ( <div> <input {...field} className="border-2" /> {meta.touched && meta.error && <div>{meta.error}</div>} </div> ); }; function App() { const handleSubmit = (values) => { console.log(values); }; return ( <div className="App"> <Formik initialValues={{ firstName: "", }} onSubmit={handleSubmit} validate={(values) => { let errors = {}; if (!values.firstName) { errors.firstName = "Required"; } return errors; }} > {() => { return ( <Form className="h-screen flex content-center flex-col justify-center"> <div className="space-x-4 flex content-center justify-center"> <div> <Field name="firstName" className="border-2" /> <ErrorMessage name="firstName" component="div" /> </div> <MySpecialField /> <button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" > Submit </button> </div> </Form> ); }} </Formik> </div> ); } export default App;