Table of Contents
What is Formik?
Formik is a library that helps developers do deal with Forms in React and React Native.
As developers we need to:
- Handle form data
- Validation
- Visual feedback with errors messages
- Form submission
With Formik, we can do all that in an easy, scalable, and performant way.
Installation
npm i --save formik
Formik Hook
Creating a Login Form with:
- Password
- Remember me
import React from "react"; /** * LoginForm Component */ const LoginForm = () => { return ( <form> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" /> <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" /> <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" id="rememberMe" /> <button style={{ display: "block" }}>submit</button> </div> </form> ); }; export default LoginForm;
Injecting Formik
- Import
useFormik
hook and addinitialValues
property with eachinput
name. - Add a
name
attritbute to eachinput
element corresponding toinitialValues
key names. - Add
formik.values[name]
tovalue
attribute on eachinput
element.- For checkboxes add
defaultChecked={formik.values[name]}
for initial value.
- For checkboxes add
- Add
formik.handleChange
toonChange
attribute on eachinput
element. - Print the
formik
object inside<pre>
tag. - Fill in all
input
elements and see the changes onformik
object.
import React from "react"; import { useFormik } from "formik"; /** * LoginForm Component */ const LoginForm = () => { const formik = useFormik({ initialValues: { email: "", password: "", rememberMe: false, }, }); return ( <form> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" name="email" value={formik.values.email} onChange={formik.handleChange} /> <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" name="password" value={formik.values.password} onChange={formik.handleChange} /> <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" name="rememberMe" id="rememberMe" onChange={formik.handleChange} defaultChecked={formik.values.rememberMe} /> <button style={{ display: "block" }}>submit</button> </div> <pre>{JSON.stringify(formik, null, 4)}</pre> </form> ); }; export default LoginForm;
Handling Form Submission
- Add
formik.handleSubmit
toonSubmit
attribute on theform
element. - Add
onSubmit
as a second property on the object insideuseFormik
hook. - log the
values
passed toonSubmit
function.
import React from "react"; import { useFormik } from "formik"; /** * LoginForm Component */ const LoginForm = () => { const formik = useFormik({ initialValues: { email: "", password: "", rememberMe: false, }, onSubmit: (values) => console.log(JSON.stringify(values, null, 4)), }); return ( <form onSubmit={formik.handleSubmit}> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" name="email" value={formik.values.email} onChange={formik.handleChange} /> <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" name="password" value={formik.values.password} onChange={formik.handleChange} /> <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" name="rememberMe" id="rememberMe" onChange={formik.handleChange} defaultChecked={formik.values.rememberMe} /> <button style={{ display: "block" }}>submit</button> </div> <pre>{JSON.stringify(formik, null, 4)}</pre> </form> ); }; export default LoginForm;
Handling Form Validation with Yup
- Install Yup
npm install yup --save
- Import Yup
import * as yup from "yup"
- Create validationSchema property on the object inside
useFormik
hook. - Submit the form with no values and see the
errors
object inside the printedformik
object.
import React from "react"; import { useFormik } from "formik"; import * as yup from "yup"; /** * LoginForm Component */ const LoginForm = () => { const formik = useFormik({ initialValues: { email: "", password: "", rememberMe: false, }, onSubmit: (values) => console.log(JSON.stringify(values, null, 4)), validationSchema: yup.object({ email: yup.string().email().required(), password: yup.string().required(), }), }); return ( <form onSubmit={formik.handleSubmit}> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" name="email" value={formik.values.email} onChange={formik.handleChange} /> <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" name="password" value={formik.values.password} onChange={formik.handleChange} /> <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" name="rememberMe" id="rememberMe" onChange={formik.handleChange} defaultChecked={formik.values.rememberMe} /> <button style={{ display: "block" }}>submit</button> </div> <pre>{JSON.stringify(formik, null, 4)}</pre> </form> ); }; export default LoginForm;
Displaying Error Messages
- Create a
<div>
tag and check forformik.errors[name]
to display the error message beneath each element that has a validation.
import React from "react"; import { useFormik } from "formik"; import * as yup from "yup"; /** * LoginForm Component */ const LoginForm = () => { const formik = useFormik({ initialValues: { email: "", password: "", rememberMe: false, }, onSubmit: (values) => console.log(JSON.stringify(values, null, 4)), validationSchema: yup.object({ email: yup.string().email().required(), password: yup.string().required(), }), }); return ( <form onSubmit={formik.handleSubmit}> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" name="email" value={formik.values.email} onChange={formik.handleChange} /> {formik.errors.email && ( <div style={{ color: "red" }}>{formik.errors.email}</div> )} <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" name="password" value={formik.values.password} onChange={formik.handleChange} /> {formik.errors.password && ( <div style={{ color: "red" }}>{formik.errors.password}</div> )} <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" name="rememberMe" id="rememberMe" onChange={formik.handleChange} defaultChecked={formik.values.rememberMe} /> <button style={{ display: "block" }}>submit</button> </div> <pre>{JSON.stringify(formik, null, 4)}</pre> </form> ); }; export default LoginForm;
Displaying Error Messages On Visited Fields
- Add
formik.handleBlur
withonBlur
attribute with allinput
elements. - Visit each
input
element and see thetouched
object inside the printedformik
object. - Add
formik.touched[name]
beforeformik.errors[name]
with the error tag element.
import React from "react"; import { useFormik } from "formik"; import * as yup from "yup"; /** * LoginForm Component */ const LoginForm = () => { const formik = useFormik({ initialValues: { email: "", password: "", rememberMe: false, }, onSubmit: (values) => console.log(JSON.stringify(values, null, 4)), validationSchema: yup.object({ email: yup.string().email().required(), password: yup.string().required(), }), }); return ( <form onSubmit={formik.handleSubmit}> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" name="email" value={formik.values.email} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.touched.email && formik.errors.email && ( <div style={{ color: "red" }}>{formik.errors.email}</div> )} <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" name="password" value={formik.values.password} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.touched.password && formik.errors.password && ( <div style={{ color: "red" }}>{formik.errors.password}</div> )} <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" name="rememberMe" id="rememberMe" onChange={formik.handleChange} onBlur={formik.handleBlur} defaultChecked={formik.values.rememberMe} /> <button style={{ display: "block" }}>submit</button> </div> <pre>{JSON.stringify(formik, null, 4)}</pre> </form> ); }; export default LoginForm;
Custom Validation Messeges
You can pass a custom validation message on each field as a string argument of the yup validation function.
import React from "react"; import { useFormik } from "formik"; import * as yup from "yup"; /** * LoginForm Component */ const LoginForm = () => { const formik = useFormik({ initialValues: { email: "", password: "", rememberMe: false, }, onSubmit: (values) => console.log(JSON.stringify(values, null, 4)), validationSchema: yup.object({ email: yup .string() .email("Please enter a valid email address") .required("Email field is required"), password: yup.string().required("Password field is required"), }), }); return ( <form onSubmit={formik.handleSubmit}> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" name="email" value={formik.values.email} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.touched.email && formik.errors.email && ( <div style={{ color: "red" }}>{formik.errors.email}</div> )} <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" name="password" value={formik.values.password} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.touched.password && formik.errors.password && ( <div style={{ color: "red" }}>{formik.errors.password}</div> )} <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" name="rememberMe" id="rememberMe" onChange={formik.handleChange} onBlur={formik.handleBlur} defaultChecked={formik.values.rememberMe} /> <button style={{ display: "block" }}>submit</button> </div> <pre>{JSON.stringify(formik, null, 4)}</pre> </form> ); }; export default LoginForm;
Code Refactor
Let us make our code more organized and decrease the lines of code by doing the following:
- Substitute
value={formik.values[name]} onChange={formik.handleChange} onBlur={formik.handleBlur}
with
{...formik.getFieldProps(name)}
- Separate
initialValues
,onSubmit
, andvalidationSchema
import React from "react"; import { useFormik } from "formik"; import * as yup from "yup"; /** * LoginForm Component */ const LoginForm = () => { const initialValues = { email: "", password: "", rememberMe: false, }; const onSubmit = (values) => console.log(JSON.stringify(values, null, 4)); const validationSchema = yup.object({ email: yup .string() .email("Please enter a valid email address") .required("Email field is required"), password: yup.string().required("Password field is required"), }); const formik = useFormik({ initialValues, onSubmit, validationSchema, }); return ( <form onSubmit={formik.handleSubmit}> <div style={{ padding: 20 }}> <label htmlFor="email" style={{ display: "block" }}> email </label> <input type="email" id="email" name="email" {...formik.getFieldProps("email")} /> {formik.touched.email && formik.errors.email && ( <div style={{ color: "red" }}>{formik.errors.email}</div> )} <label htmlFor="password" style={{ display: "block" }}> password </label> <input type="password" id="password" name="password" {...formik.getFieldProps("password")} /> {formik.touched.password && formik.errors.password && ( <div style={{ color: "red" }}>{formik.errors.password}</div> )} <label htmlFor="rememberMe" style={{ display: "block" }}> remember me </label> <input type="checkbox" name="rememberMe" id="rememberMe" defaultChecked={formik.values.rememberMe} {...formik.getFieldProps("rememberMe")} /> <button style={{ display: "block" }}>submit</button> </div> <pre>{JSON.stringify(formik, null, 4)}</pre> </form> ); }; export default LoginForm;
Top comments (4)
Instead of written formilk.something
Try to destruct it it will make the code much cleaner
Hello, I have created multi-step form. In that There are 3 step submit button appere in 3rd step but in 2nd step on click next button it submit
here is link of code
github.com/MDMohsinGhazi/multi-ste...
Thank you!!!
Really a good article covering the usage of formik and yup.