23
Building React Forms Painlessly With Formik
Forms are really important for us as web developers, because on every application you do in real life, you are probably going to need to do forms.
Building forms in React can be tiring and can get messy. If you have a small form with few data inputs you can build it without using a form library. The same can't be said when building forms with larger number of data inputs and validation rules.
In this article, I am going to demonstrate building forms with Formik. I am also going to go into the features Formik provides. This is the screenshot of what we will be building:
We will start by creating a React application on our local environment. To do this, we open the command line and go to a document folder using:
cd documents
After that we create our React application and install bootstrap
to add a little bit of styles to our form by using the classes provided by bootstrap
.
Run the following commands in the command line:
npx create-react-app formik-forms
cd formik-forms
npm install react-bootstrap bootstrap
npm install formik
yarn start
The commands above should get us to the point where we have created a new React project, installed pretty much the needed dependencies, and are running the app locally.
After the React project has been created on your computer, open it with your preferred code editor and create a new file called userForm.js
. Add the following code to the new file created:
import React from 'react'
import {Formik} from 'formik'
import 'bootstrap/dist/css/bootstrap.min.css'
We will be using functions, functional components, and the following form template I have created already with bootstrap. Since you have installed and imported bootstrap into your React project, you shouldn't have any issues with this.
So you can copy and paste the template below into your own userForm.js
file or better still create your own using bootstrap
<div className="container">
<div className="col-md-12 mt-5">
<form>
<h4 className="mb-3">Personal information</h4>
<div className="row">
<div className="col-md-6 mb-3">
<label htmlFor="firstname">First name</label>
<input type="text" className="form-control" id="firstname" name="firstname"/>
</div>
<div className="col-md-6 mb-3">
<label htmlFor="lastname">Last name</label>
<input type="text" className="form-control" id="lastname" name="lastname"/>
</div>
</div>
<div className="mb-3">
<label htmlFor="email">Email</label>
<input type="email" className="form-control" id="email" name="email" placeholder="[email protected]"/>
</div>
<div className="row">
<div className="col-md-5 mb-3">
<label htmlFor="country">Country</label>
<select className="custom-select d-block w-100" id="country" name="country">
<option value="">Choose...</option>
<option value="NIG">Nigeria</option>
<option value="GH">Ghana</option>
<option value="SA">South Africa</option>
</select>
</div>
<div className="col-md-4 mb-3">
<label htmlFor="state">State</label>
<select className="custom-select d-block w-100" id="state" name="state">
<option value="">Choose...</option>
<option value="lagos">Lagos</option>
<option value="east legion">East Legion</option>
<option value="cape town">Cape Town</option>
</select>
</div>
<div className="col-md-3 mb-3">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" id="zip" name="zip"/>
</div>
</div>
<hr className="mb-4"/>
<button className="btn btn-primary btn-lg btn-block" type="submit">
Submit
</button>
</form>
</div>
</div>
Still in our userForm.js file, I will be wrapping the form components in the Formik
component we imported earlier, but before that, we will have to declare our Formik
component and provide a function that gives us props with a lot of method that we will use inside our form.
const UserForm = () => {
return (
<Formik>
{ ({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit
}) => (
) }
</Formik>
)
}
In the code above, I have de-structured the various methods we need from the props, this will make it easier for us to use as properties in our form. For example, we can now do values
, instead of props.values
.
The next thing to do is to return some JSX or in this case our form
components in the Formik
function.
const UserForm = () => {
return (
<Formik>
{ ({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit
}) => (
<div className="container">
<div className="col-md-12 mt-5">
<form>
<h4 className="mb-3">Personal information</h4>
<div className="row">
<div className="col-md-6 mb-3">
<label htmlFor="firstname">First name</label>
<input type="text" className="form-control" id="firstname" name="firstname"/>
</div>
<div className="col-md-6 mb-3">
<label htmlFor="lastname">Last name</label>
<input type="text" className="form-control" id="lastname" name="lastname"/>
</div>
</div>
<div className="mb-3">
<label htmlFor="email">Email</label>
<input type="email" className="form-control" id="email" name="email" placeholder="[email protected]"/>
</div>
<div className="row">
<div className="col-md-5 mb-3">
<label htmlFor="country">Country</label>
<select className="custom-select d-block w-100" id="country" name="country">
<option value="">Choose...</option>
<option value="NIG">Nigeria</option>
<option value="GH">Ghana</option>
<option value="SA">South Africa</option>
</select>
</div>
<div className="col-md-4 mb-3">
<label htmlFor="state">State</label>
<select className="custom-select d-block w-100" id="state" name="state">
<option value="">Choose...</option>
<option value="lagos">Lagos</option>
<option value="east legion">East Legion</option>
<option value="cape town">Cape Town</option>
</select>
</div>
<div className="col-md-3 mb-3">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" id="zip" name="zip"/>
</div>
</div>
<hr className="mb-4"/>
<button className="btn btn-primary btn-lg btn-block" type="submit">
Submit
</button>
</form>
</div>
</div>
) }
</Formik>
)
}
Now the Formik
component requires properties. One a property that helps formik to know what we are going to be using on the form i.e the values that Formik
component will be controlling and another property that controls the submission of the form when a submit button is clicked.
const UserForm = () => {
return (
<Formik
initialValues={{
firstname: ''
lastname: ''
email: ''
country: ''
state: ''
zip: ''
}}
onSubmit={() => {
console.log('form submitted')
}}
>
{ ({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit
}) => (
<div className="container">
<div className="col-md-12 mt-5">
<form>
<h4 className="mb-3">Personal information</h4>
<div className="row">
<div className="col-md-6 mb-3">
<label htmlFor="firstname">First name</label>
<input type="text" className="form-control" id="firstname" name="firstname"/>
</div>
<div className="col-md-6 mb-3">
<label htmlFor="lastname">Last name</label>
<input type="text" className="form-control" id="lastname" name="lastname"/>
</div>
</div>
<div className="mb-3">
<label htmlFor="email">Email</label>
<input type="email" className="form-control" id="email" name="email" placeholder="[email protected]"/>
</div>
<div className="row">
<div className="col-md-5 mb-3">
<label htmlFor="country">Country</label>
<select className="custom-select d-block w-100" id="country" name="country">
<option value="">Choose...</option>
<option value="NIG">Nigeria</option>
<option value="GH">Ghana</option>
<option value="SA">South Africa</option>
</select>
</div>
<div className="col-md-4 mb-3">
<label htmlFor="state">State</label>
<select className="custom-select d-block w-100" id="state" name="state">
<option value="">Choose...</option>
<option value="lagos">Lagos</option>
<option value="east legion">East Legion</option>
<option value="cape town">Cape Town</option>
</select>
</div>
<div className="col-md-3 mb-3">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" id="zip" name="zip"/>
</div>
</div>
<hr className="mb-4"/>
<button className="btn btn-primary btn-lg btn-block" type="submit">
Submit
</button>
</form>
</div>
</div>
) }
</Formik>
)
}
In the form
component, you will notice all input components has an id
. It is these id
values that we use as the keys in the initialValues
object. For the form submission, I will just be displaying a string in the browser's console console.log('form submitted')
since we are not working with a server or database in this article.
We will need to link the initialValues
property to the actual input we will be getting from our form by adding a value
property to the input
components and accessing users input from the values
method.
const UserForm = () => {
return (
<Formik
initialValues={{
firstname: ''
lastname: ''
email: ''
country: ''
state: ''
zip: ''
}}
onSubmit={() => {
console.log('form submitted')
}}
>
{ ({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit
}) => (
<div className="container">
<div className="col-md-12 mt-5">
<form>
<h4 className="mb-3">Personal information</h4>
<div className="row">
<div className="col-md-6 mb-3">
<label htmlFor="firstname">First name</label>
<input
type="text"
className="form-control"
id="firstname"
name="firstname"
value={values.firstname}
/>
</div>
<div className="col-md-6 mb-3">
<label htmlFor="lastname">Last name</label>
<input
type="text"
className="form-control"
id="lastname"
name="lastname"
value={values.lastname}
/>
</div>
</div>
<div className="mb-3">
<label htmlFor="email">Email</label>
<input
type="email"
className="form-control"
id="email"
name="email"
placeholder="[email protected]"
value={values.email}
/>
</div>
<div className="row">
<div className="col-md-5 mb-3">
<label htmlFor="country">Country</label>
<select
className="custom-select d-block w-100"
id="country"
name="country"
value={values.country}
>
<option value="">Choose...</option>
<option value="NIG">Nigeria</option>
<option value="GH">Ghana</option>
<option value="SA">South Africa</option>
</select>
</div>
<div className="col-md-4 mb-3">
<label htmlFor="state">State</label>
<select
className="custom-select d-block w-100"
id="state"
name="state"
value={values.state}
>
<option value="">Choose...</option>
<option value="lagos">Lagos</option>
<option value="east legion">East Legion</option>
<option value="cape town">Cape Town</option>
</select>
</div>
<div className="col-md-3 mb-3">
<label htmlFor="zip">Zip</label>
<input
type="text"
className="form-control"
id="zip"
name="zip"
value={values.zip}
/>
</div>
</div>
<hr className="mb-4"/>
<button className="btn btn-primary btn-lg btn-block" type="submit">
Submit
</button>
</form>
</div>
</div>
) }
</Formik>
)
}
Finally we will need to add an onSubmit
property to our form
component and pass in the handleSubmit
method from the Formik
component, and also add an onChange
property to the input components and pass in the handleChange
method.
const UserForm = () => {
return (
<Formik
initialValues={{
firstname: ''
lastname: ''
email: ''
country: ''
state: ''
zip: ''
}}
onSubmit={() => {
console.log('form submitted')
}}
>
{ ({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit
}) => (
<div className="container">
<div className="col-md-12 mt-5">
<form onSubmit={handleSubmit}>
<h4 className="mb-3">Personal information</h4>
<div className="row">
<div className="col-md-6 mb-3">
<label htmlFor="firstname">First name</label>
<input
type="text"
className="form-control"
id="firstname"
name="firstname"
value={values.firstname}
/>
</div>
<div className="col-md-6 mb-3">
<label htmlFor="lastname">Last name</label>
<input
type="text"
className="form-control"
id="lastname"
name="lastname"
value={values.lastname}
/>
</div>
</div>
<div className="mb-3">
<label htmlFor="email">Email</label>
<input
type="email"
className="form-control"
id="email"
name="email"
placeholder="[email protected]"
value={values.email}
/>
</div>
<div className="row">
<div className="col-md-5 mb-3">
<label htmlFor="country">Country</label>
<select
className="custom-select d-block w-100"
id="country"
name="country"
value={values.country}
>
<option value="">Choose...</option>
<option value="NIG">Nigeria</option>
<option value="GH">Ghana</option>
<option value="SA">South Africa</option>
</select>
</div>
<div className="col-md-4 mb-3">
<label htmlFor="state">State</label>
<select
className="custom-select d-block w-100"
id="state"
name="state"
value={values.state}
>
<option value="">Choose...</option>
<option value="lagos">Lagos</option>
<option value="east legion">East Legion</option>
<option value="cape town">Cape Town</option>
</select>
</div>
<div className="col-md-3 mb-3">
<label htmlFor="zip">Zip</label>
<input
type="text"
className="form-control"
id="zip"
name="zip"
value={values.zip}
/>
</div>
</div>
<hr className="mb-4"/>
<button className="btn btn-primary btn-lg btn-block" type="submit">
Submit
</button>
</form>
</div>
</div>
) }
</Formik>
)
}
In my next article, which will be a sequel to this one, I will be expanding on the form we created here by doing some form validation with Yup a library used for easy form validation.
Well that does it for this article. I hope you do find article useful.
Thanks and have a nice read.
23