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
useFormikhook and addinitialValuesproperty with eachinputname. - Add a
nameattritbute to eachinputelement corresponding toinitialValueskey names. - Add
formik.values[name]tovalueattribute on eachinputelement.- For checkboxes add
defaultChecked={formik.values[name]}for initial value.
- For checkboxes add
- Add
formik.handleChangetoonChangeattribute on eachinputelement. - Print the
formikobject inside<pre>tag. - Fill in all
inputelements and see the changes onformikobject.
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.handleSubmittoonSubmitattribute on theformelement. - Add
onSubmitas a second property on the object insideuseFormikhook. - log the
valuespassed toonSubmitfunction.
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
useFormikhook. - Submit the form with no values and see the
errorsobject inside the printedformikobject.
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.handleBlurwithonBlurattribute with allinputelements. - Visit each
inputelement and see thetouchedobject inside the printedformikobject. - 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.