Getting Started with React Formik & Yup
Youssef Zidan
Posted on March 19, 2021
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;
💖 💪 🙅 🚩
Youssef Zidan
Posted on March 19, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.