Managing forms in any application requires the following things,
- Updating state value on form control change.
- Updating touched / errors state for form control to show required messages.
- Form Validation.
- Updating form state like dirty and valid.
In React it is a bit complex to manage these things, we need to manage each thing manually using state. There are many popular libraries available to manage these things. In this article, we will see one such library,
Formik - one of the popular libraries for managing forms in React.
Formik
Formik provides all the required features out-of-the-box for managing forms,
- Initializing form state
- Updating value state on control value changes
- Updating errors / touched state on form control change
- Handler function like handleBlur, handleChange which updates the form state, handleSubmit which calls the onSubmit handler on form submit
- Form validation mechanism
- Form state like valid, dirty, submitting count
and many more. So let's get started, I am using online editor
stackblitz for this sample application.
We will create a registration form and manage its state with Formik.
Setup Form Template
Let's first set up the registration form template as shown below,
You can create this form in any component, I have created it in App.js/App.jsx.
-
-
- import React from 'react';
- import './style.css';
-
- export default function App() {
- return (
- <div class="root">
- <div class="form">
- <h1> Registration </h1>
- <form>
- <div class="form-group">
- <label> First Name </label>
- <input type="text" />
- </div>
- <div class="form-group">
- <label> Last Name </label>
- <input type="text" />
- </div>
- <div class="form-group">
- <label> Email Id </label>
- <input type="text" />
- </div>
- <div class="form-group">
- <label> Mobile Number </label>
- <input type="text" />
- </div>
- <div class="form-group">
- <label> Gender </label>
- <select>
- <option value="">Select</option>
- <option value="male">Male</option>
- <option value="female">Female</option>
- </select>
- </div>
- <div class="form-group">
- <label> Address </label>
- <textarea type="text" />
- </div>
- <div>
- <button class="btn-primary">Submit </button>
- <button class="btn-secondary">Reset </button>
- </div>
- </form>
- </div>
- <div class="form-state">
- <h4>Form State</h4>
- </div>
- </div>
- );
- }
-
-
- * {
- font-family: Lato;
- }
-
- .root {
- padding: 0px 10px;
- display: grid;
- }
-
- @media screen and (min-width: 800px) {
- .root {
- grid-template-columns: 50% 50%;
- }
- }
-
- .form-group {
- display: grid;
- grid-template-columns: 30% 50%;
- margin: 10px 0px;
- }
-
- input,
- select,
- textarea {
- padding: 5px;
- border-radius: 0px;
- border: 1px solid black;
- }
-
- button {
- margin-right: 5px;
- padding: 10px;
- border: none;
- }
- .btn-primary {
- background: lightblue;
- }
Install Formik
Install formik in your application with the following command,
- npm install --save formik
Use Formik To Manage Form
We can use formik to manage forms using <Formik /> HOC or useFormik() hook. In this article, we will use the useFormik() hook.
Initialize the Form State
- export default function App(){
-
- const formik = useFormik({
- initialValues: {
- firstName: '',
- lastName: '',
- emailId: '',
- mobileNumber: undefined,
- gender: '',
- address: ''
- },
- });
-
-
- }
Map the Input Control
- Formik uses the name or id property of input control to map it with form state,
- We need to set the value property of form state
- Need to register the formik handleChange handler with onChange event of input control
- <input type="text" name="firstName" value={formik.values.firstName} onChange={formik.handleChange} />
Here name should be the same as the property initialized in formik state initial values.
We need to set the above properties for all form control as shown below,
-
-
- import React from 'react';
- import './style.css';
- import { useFormik } from 'formik';
-
- export default function App() {
- const formik = useFormik({
- initialValues: {
- firstName: '',
- lastName: '',
- emailId: '',
- mobileNumber: undefined,
- gender: '',
- address: ''
- }
- });
-
- return (
- <div class="root">
- <div class="form">
- <h1> Registration </h1>
- <form>
- <div class="form-group">
- <label> First Name </label>
- <input
- type="text"
- name="firstName"
- value={formik.values.firstName}
- onChange={formik.handleChange}
- />
- </div>
- <div class="form-group">
- <label> Last Name </label>
- <input
- type="text"
- name="lastName"
- value={formik.values.lastName}
- onChange={formik.handleChange}
- />
- </div>
- <div class="form-group">
- <label> Email Id </label>
- <input
- type="text"
- name="emailId"
- value={formik.values.emailId}
- onChange={formik.handleChange}
- />
- </div>
- <div class="form-group">
- <label> Mobile Number </label>
- <input
- type="text"
- name="mobileNumber"
- value={formik.values.mobileNumber}
- onChange={formik.handleChange}
- />
- </div>
- <div class="form-group">
- <label> Gender </label>
- <select
- name="gender"
- value={formik.values.gender}
- onChange={formik.handleChange}
- >
- <option value="">Select</option>
- <option value="male">Male</option>
- <option value="female">Female</option>
- </select>
- </div>
- <div class="form-group">
- <label> Address </label>
- <textarea
- type="text"
- name="address"
- value={formik.values.address}
- onChange={formik.handleChange}
- />
- </div>
- <div>
- <button class="btn-primary">Submit </button>
- <button class="btn-secondary">Reset </button>
- </div>
- </form>
- </div>
- <div class="form-state">
- <h4>Form State</h4>
- <h5>Values:</h5>
- <code>
- <pre>{JSON.stringify(formik.values, null, 2)}</pre>
- </code>
- </div>
- </div>
- );
- }
Now test your form. As you can see below, we are able to successfully map the form controls.
Reduce boilerplate code
The above code is perfect, but as you see in the code there is so much boilerplate code, we need to set common props for each form control just the name of the control is different. We can reduce this boilerplate code with the formik helper function getFieldProps(fieldName), which returns the following properties,
- {
-
- value: Value;
-
- name: string;
-
- multiple?: boolean;
-
- checked?: boolean;
-
- onChange: FormikHandlers['handleChange'];
-
- onBlur: FormikHandlers['handleBlur'];
- }
We just need to spread these properties in our form control as shown below,
- <input type="text" {...formik.getFieldProps('firstName')} />
As you can see we don't need to write all other properties. Update in the same way on other form controls.
Handle Form Submit
Formik provides handleSubmit helper function which we need to register on submit event of the form. Once we will submit the form it will call the onSubmit handler specified at the time of formik initialization with useFormik hook as shown below,
- import React from 'react';
- import './style.css';
- import { useFormik } from 'formik';
-
- export default function App() {
- const formik = useFormik({
- initialValues: {
- firstName: '',
- lastName: '',
- emailId: '',
- mobileNumber: undefined,
- gender: '',
- address: ''
- },
- onSubmit: values => {
- alert(
- 'Registration Form Submitted \n ' + JSON.stringify(values, null, 2)
- );
- }
- });
-
- return (
- <div class="root">
- <form onSubmit={formik.handleSubmit}>
- {}
- </form>
- </div>
- );
- }
Reset Form
We can reset the form by using the resetForm() method of formik. We can register it on the onClick event of the reset button.
Final Code
-
-
- import React from 'react';
- import './style.css';
- import { useFormik } from 'formik';
-
- export default function App() {
- const formik = useFormik({
- initialValues: {
- firstName: '',
- lastName: '',
- emailId: '',
- mobileNumber: undefined,
- gender: '',
- address: ''
- },
- onSubmit: values => {
- alert(
- 'Registration Form Submitted \n ' + JSON.stringify(values, null, 2)
- );
- formik.resetForm();
- }
- });
-
- return (
- <div class="root">
- <div class="form">
- <h1> Registration </h1>
- <form onSubmit={formik.handleSubmit}>
- <div class="form-group">
- <label> First Name </label>
- <input type="text" {...formik.getFieldProps('firstName')} />
- </div>
- <div class="form-group">
- <label> Last Name </label>
- <input type="text" {...formik.getFieldProps('lastName')} />
- </div>
- <div class="form-group">
- <label> Email Id </label>
- <input type="text" {...formik.getFieldProps('emailId')} />
- </div>
- <div class="form-group">
- <label> Mobile Number </label>
- <input type="text" {...formik.getFieldProps('mobileNumber')} />
- </div>
- <div class="form-group">
- <label> Gender </label>
- <select {...formik.getFieldProps('gender')}>
- <option value="">Select</option>
- <option value="male">Male</option>
- <option value="female">Female</option>
- </select>
- </div>
- <div class="form-group">
- <label> Address </label>
- <textarea type="text" {...formik.getFieldProps('address')} />
- </div>
- <div>
- <button type="submit" class="btn-primary">
- Submit
- </button>
- <button
- type="reset"
- class="btn-secondary"
- onClick={formik.resetForm}
- >
- Reset
- </button>
- </div>
- </form>
- </div>
- <div class="form-state">
- <h4>Form State</h4>
- <h5>Values:</h5>
- <code>
- <pre>{JSON.stringify(formik.values, null, 2)}</pre>
- </code>
- </div>
- </div>
- );
- }
Final Output
Check out the Live Application
here.
Summary
In this article, we have seen how to manage React forms easily with formik. We have seen step-by-step formik setup in react, in the
next article, we will see form validation using formik.
I hope you like this article, give your valuable feedback and suggestion in the comment section🙂.
Next Article:
References