For my TLDR people skip to the TLDR section.
Intro
Forms in React can be complex and tedious especially when working with controlled forms. Controlling state, adding validations, and handling submits can be a hassle when you have multiple form entries. Thankfully, libraries like Formik and Yup can help you add these features in a way that's simple and clean. So, let’s talk about how to use them.
Formik
“Formik is a popular open-source library for building and processing form data in React applications” – freecodecamp.orgYup
“Yup is a schema builder for runtime value parsing and validation” – npmjs.com
Set up
1. Set up your React Project
I’m assuming most of you are already past this step but if not, you want to create your React project. You can follow along with the docs here, it’s fairly simple and straightforward.
2. Installing Formik and Yup
To install formik and yup, you just need to run the command in your terminal: npm install formik yup
. Once those dependencies finish installing you’re pretty much ready to use them.
3. Create a form
Once again, I’m assuming most of you are already passed this step. But just in case, here is a link to a great tutorial on how to make React controlled forms.
Using Formik and Yup
1. Import Formik
At the top of the React component you want to use Formik in, you need to import it before you can use Formik.
import React from 'react';
import { useFormik } from 'formik';
const MyForm = () => {
// Your form logic will go here
};
export default MyForm;
2. Import Yup
For Yup we have 2 different options. Since Yup helps with data validation it creates a schema. We can write this schema in the same component or we can write it in another file and import it. Both have their pros and cons but in general if you have multiple schemas it’s probably in your best interest to create a separate file. To do this, you first want to create a new folder in your src
folder called schemas. In your schemas folder you want to create a JSX file (most people would just call it index.jsx
). In your index.jsx
file, you want to import Yup just like this: import * as yup from 'yup'
. We don’t have schemas yet but we’ll cover that later when it becomes applicable.
Application
1. Prefix
For demonstration, I’m going to make a simple sign up form which includes a username and password. In your project you can build upon these ideas no matter how many inputs your form has. Here is what my form would look like if I were to build it in React without formik or yup:
import React, { useState } from "react";
function SignupForm () {
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
function handleSubmit(e) {
e.preventDefault();
fetch(//your promise)
}
return (
<form autoComplete="off" onSubmit={handleSubmit}>
<label>Username</label>
<input
type="text"
id="username"
placeholder="Enter your username..."
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<label>Password</label>
<input
type="password"
id="password"
placeholder="Enter your password..."
value={password}
onChange={(e) =>setPassword(e.target.value)}
/>
<button type="submit">
Signup
</button>
</form>
)
};
export default LoginForm;
2. Creating a Schema
In our index.jsx
file we created in the schema folder, let’s first create a schema or some validations we want to use in our form. Our file should look like this:
import * as yup from "yup"
To define our schema we want to type this:
export const schema = yup.object().shape({})
export
will allow us to export this schema to any component it’s needed. Inside .shape({})
we are going to define our validations. Here is a simple validation schema:
export const schema = yup.object().shape({
username: yup.string("Please enter a valid name").required("Required"),
password: yup.string().min(5).required("Required"),
})
For username we are saying that it needs to be a string with .string()
and it cannot be empty (or null) with .required()
. Inside of those methods we type an error message as a string.
For password we are once again saying that it needs to be a string with .string
and it cannot be empty (or null) with .required()
. We also state that the password needs to be a minimum length of 5.
Our index.jsx
will look something like this:
import * as yup from "yup"
export const basicSchema = yup.object().shape({
username: yup.string("Please enter a valid name").required("Required"),
password: yup.string().min(5).required("Required"),
})
3. Incorporating Formik
To use formik we declare it as so:
const formik = useFormik({})
We can destructure formik to access certain elements. First let’s focus on state management. Let’s destructure our formik variable:
const { values, handleChange, handleSubmit } = useFormik({})
There are more elements, but these are the basic ones we need. For state management, we no longer need useState
. It’s now replaced by values
and handleChange
. Let's make our values
:
const { values, handleChange, handleSubmit} = useFormik({
initialValues: {
username: "",
password: "",
},
})
Then change our form as so:
<label>Username</label>
<input
type="text"
id="username"
placeholder="Enter your username..."
value={values.username}
onChange={handleChange}
/>
<label>Password</label>
<input
type="password"
id="password"
placeholder="Enter your password..."
value={values.password}
onChange={handleChange}
/>
After we handle state management we need to add our schema here. Since we created a separate file, all we have to do is import and call it for the validationSchema
:
import { basicSchema } from '../schemas'
// our component
const { values, handleChange, handleSubmit} = useFormik({
initialValues: {
username: "",
password: "",
},
validationSchema: basicSchema,
})
Now let's add onSubmit
function underneath validationSchema
:
// our component
const { values, handleChange, handleSubmit} = useFormik({
initialValues: {
username: "",
password: "",
},
validationSchema: basicSchema,
onSubmit: (values) => {
fetch(// your promise)
},
})
You could also keep the onSubmit
function separate like this:
const onSubmit = (values) => {
fetch(// your promise)
const { values, handleChange, handleSubmit} = useFormik({
initialValues: {
username: "",
password: "",
},
validationSchema: basicSchema,
onSubmit,
})
Conclusion
Formik and Yup are great tools to help make React forms more responsive and easier to manage. With state management, validations, and a cleaner syntax they can help enhance your project. For more information on Formik or Yup check out the documentation.
TDLR
//imports
import React from "react";
import { useFormik } from 'formik';
import { basicSchema } from '../schemas';
//form component
function SignupForm() {
//formik
// declare and destucture
const { values, handleChange, handleSubmit} = useFormik({
// setup values
initialValues: {
username: "",
password: "",
},
// setup schema/validation
validationSchema: basicSchema,
// submit function
onSubmit: (values) => {
fetch(// your promise)
},
})
//form
return (
<label>Username</label>
<input
type="text"
id="username"
placeholder="Enter your username..."
value={values.username}
onChange={handleChange}
/>
<label>Password</label>
<input
type="password"
id="password"
placeholder="Enter your password..."
value={values.password}
onChange={handleChange}
/>
)
}
//schemas folder => index.jsx
import * as yup from "yup"
//schema for formik
export const basicSchema = yup.object().shape({
// add validation for each value
username: yup.string("Please enter a valid name").required("Required"),
password: yup.string().min(5).required("Required"),
})
Sources
- https://www.freecodecamp.org/news/build-react-forms-with-formik-library/#:~:text=What%20is%20Formik%3F,a%20React%20application%20more%20enjoyable
- https://www.npmjs.com/package/yup
- https://create-react-app.dev/docs/getting-started/
- https://www.youtube.com/watch?v=IkMND33x0qQ
- https://formik.org/docs/overview
- https://github.com/jquense/yup/tree/pre-v1
Top comments (2)
Nice explaination but Formik is not maintained by the developers now and the last release was out a year ago, it might be depreciated in future, i would recommend using "react-hooks-form", similar to formik and easy to use
Cheers🙌
Thanks for letting me know!