How To Create Forms With Dynamic Fields using React And Formik
Created By Christian Deacon
In this guide, we'll be going over how to create a form with dynamic fields using React, TypeScript or JavaScript, and Formik.
The form in this guide will represent a list of people. Each person will have first name, last name, and age fields. You will be able to add another person to the list by clicking the Add Person button and remove a specific person by clicking the Remove button underneath the list of fields for that specific person.
We will NOT be adding any styling to our form using CSS as well! This is to simplify the guide. With that said, this guide and its source code are all stored in a GitHub repository here.
Why Formik?
Formik is the world's most popular open source form library for React and React Native. It comes with battle-tested solutions for input validation, formatting, masking, arrays, and error handling. This means you spend less time writing form code and more time building your next big thing.
These features make creating dynamic forms like the one we'll be creating in this guide easier and is why we chose to utilize Formik!
My Development Setup
Before continuing, I just wanted to briefly go over my development setup.
I am writing this guide and developing the React application using Visual Studio Code as my IDE with the Remote SSH extension which allows me to write/execute code on my VM running Debian 12 (Linux) directly. The VM is located on one of my home servers I have running locally under its own VLAN.
The VM is running Node.js version 20.10.0
with NPM version 10.2.4
. It also has 6 GBs of DDR4 RAM and two vCPU cores.
Prerequisites
React, TypeScript, and Formik are required for this guide. We will also be using Node.js with its package manager, NPM.
Installing Node.js & NPM
On Debian/Ubuntu-based systems, you may install the nodejs
and npm
packages using the apt
package manager. The following command should do the trick.
1sudo apt install -y nodejs npm
However, this will most likely install an outdated/stable version of Node.js. While the stable version of Node should work fine for this guide, if you want to install a more up-to-date version of Node.js, feel free to take a look at this guide! Additionally, you may read this guide if you want to install Node.js and NPM on a Linux OS other than Debian/Ubuntu.
For Windows builds, you may refer to the downloads page here.
Creating A React Application
You can create a React application using npx
after installing Node.js and NPM above.
1npx create-react-app <name> --template typescript
If you plan on using TypeScript, make sure to pass --template typescript
. Otherwise, you may omit this flag to use JavaScript.
Installing Formik
To install Formik, you may use the following npm
command.
1npm install --save formik
NPM Audit
Before continuing, you may also want to perform an audit using npm
to ensure there aren't any vulnerabilities in our installed packages. You may use the following commands to do so.
1# Perform an audit and receive a vulnerabilities report. 2npm audit 3 4# Attempt to update packages to resolve vulnerabilities without potentially breaking packages. 5npm audit fix
Making Our Form
We will be creating our form inside of the src/App.tsx
source file (or src/App.jsx
if you're using JavaScript).
Import Elements From Formik & Cleaning Imports
We want to import elements we'll be using from Formik. With that said, I've cleaned up other imports we won't need such as the logo and CSS file.
We will import Formik
, Form
, Field
, and FieldArray
from the Formik package.
1import { Formik, Form, Field, FieldArray } from 'formik'
Initializing An Empty Person Value
Next, we'll want to create an empty person object that represents the default values of a person. In this case, the first and last names will be an empty string while we'll use a default age of 21
.
1const emptyPerson = { 2 first: "", 3 last: "", 4 age: 21 5}
At this point, our code above the App()
function should look something like the following.
1import { Formik, Form, Field, FieldArray } from 'formik' 2 3const emptyPerson = { 4 first: "", 5 last: "", 6 age: 21 7}
Creating The Base Form
Inside of our App()
function, we can create a simple form using the <Formik>
and <Form>
elements. We'll need to pass two props to the <Formik>
element. The first prop is our initial values and the second prop is an on submit callback function.
In this guide, our on submit callback function will simply print all values to the client's web developer console using console.log()
when the Add People button is clicked. Our initial values will consist of a people
array set to one single emptyPerson
item.
1function App() { 2 return ( 3 <Formik 4 initialValues={{ 5 people: [emptyPerson] 6 }} 7 onSubmit={(values) => { 8 console.log(values) 9 }} 10 > 11 {({ values }) => ( 12 <Form> 13 <h1>People</h1> 14 [People Array] 15 <div> 16 <button type="submit">Add People!</button> 17 </div> 18 </Form> 19 )} 20 </Formik> 21 ) 22} 23 24export default App;
Creating People Array
Next, we'll want to create a field array using the <FieldArray>
element with our people
array. We'll be utilizing the push()
and remove()
functions from the <FieldArray>
element to add and remove people from the people
array.
We'll be replacing the [People Array]
text above with the following code.
1<FieldArray name="people"> 2 {({ push, remove }) => ( 3 <> 4 {values.people.map((_person, index) => { 5 return ( 6 [Person] 7 ) 8 })} 9 [Add Button] 10 </> 11 )} 12</FieldArray>
Creating The Add Person Button
To create our add person button, we'll be utilizing the push()
function with emptyPerson
as the argument to add another person to the people
array with our default person values.
We'll be replacing the [Add Button]
text above with the following code.
1<div> 2 <button 3 type="button" 4 onClick={() => push(emptyPerson)} 5 >Add Person</button> 6</div>
Creating Fields For Each Person
Now we'll want to create fields using the <Field>
element when mapping through our people
array. Remember, we will be displaying first name, last name, and age fields for each person.
We'll be replacing the [Person]
text above with the following code.
1// To simplify code, let's build the starting string of our field names for this specific person which is `people[index]`. 2const startName = `people[${index.toString()}]` 3 4return ( 5 <div key={`person-${index.toString()}`}> 6 <h2>Person #{(index + 1).toString()}</h2> 7 <div> 8 <label htmlFor={`${startName}.first`}>First Name</label> 9 <Field name={`${startName}.first`} /> 10 </div> 11 <div> 12 <label htmlFor={`${startName}.last`}>Last Name</label> 13 <Field name={`${startName}.last`} /> 14 </div> 15 <div> 16 <label htmlFor={`${startName}.age`}>Age</label> 17 <Field 18 type="number" 19 name={`${startName}.age`} 20 /> 21 </div> 22 [Remove Button] 23 </div> 24)
Creating The Remove Person Button
To create a button to remove the specific person, we will utilize the remove()
function with the index of the person in the array as the argument. Since we pass index
in our mapping function, this is pretty simple.
We'll be replacing the [Remove Button]
text above with the following code.
1<div> 2 <button 3 type="button" 4 onClick={() => remove(index)} 5 >Remove</button> 6</div>
Final Code
Our final code should look something like below!
1import { Formik, Form, Field, FieldArray } from 'formik' 2 3const emptyPerson = { 4 first: "", 5 last: "", 6 age: 21 7} 8 9function App() { 10 return ( 11 <Formik 12 initialValues={{ 13 people: [emptyPerson] 14 }} 15 onSubmit={(values) => { 16 console.log(values) 17 }} 18 > 19 {({ values }) => ( 20 <Form> 21 <h1>People</h1> 22 <FieldArray name="people"> 23 {({ push, remove }) => ( 24 <> 25 {values.people.map((_person, index) => { 26 // To simplify code, let's build the starting string of our field names for this specific person which is `people[index]`. 27 const startName = `people[${index.toString()}]` 28 29 return ( 30 <div key={`person-${index.toString()}`}> 31 <h2>Person #{(index + 1).toString()}</h2> 32 <div> 33 <label htmlFor={`${startName}.first`}>First Name</label> 34 <Field name={`${startName}.first`} /> 35 </div> 36 <div> 37 <label htmlFor={`${startName}.last`}>Last Name</label> 38 <Field name={`${startName}.last`} /> 39 </div> 40 <div> 41 <label htmlFor={`${startName}.age`}>Age</label> 42 <Field 43 type="number" 44 name={`${startName}.age`} 45 /> 46 </div> 47 <div> 48 <button 49 type="button" 50 onClick={() => remove(index)} 51 >Remove</button> 52 </div> 53 </div> 54 ) 55 })} 56 <div> 57 <button 58 type="button" 59 onClick={() => push(emptyPerson)} 60 >Add Person</button> 61 </div> 62 </> 63 )} 64 </FieldArray> 65 <div> 66 <button type="submit">Add People!</button> 67 </div> 68 </Form> 69 )} 70 </Formik> 71 ); 72} 73 74export default App;
You may also find this code inside our GitHub repository here.
Testing Our Code
We won't be writing automated tests in this guide, but we will be testing our code manually.
(Optional) Cloning Our GitHub Repository
If you didn't follow the guide for your own project, you can still test the code by cloning our repository using git clone
like below.
1# Clone repository 2git clone https://github.com/deaconn-net/react-form-with-dynamic-fields-and-formik 3 4# Change directories 5cd react-form-with-dynamic-fields-and-formik 6 7# Install NPM packages 8npm install
Running The Development Server
You may use the following command to start the NPM development server.
1npm start
This should make http://localhost:3000 accessible. If you're starting the development server on another machine, you will most likely need to replace localhost
with your server's IP address and ensure port 3000/TCP
is allowed through its firewall. In my case, Visual Studio Code's Remote SSH extension automatically forwards localhost:3000
to the server's IP on port 3000
.
Preview
You should see a page like below when visiting the React application through your web browser.
Now feel free to experiment with the fields along with add/remove buttons!
Clicking The "Add People" Button
If you click the "Add People" submit button at the bottom and have some people added to your list, you should see an array outputted in the web developer console. You can normally access the web developer console using the F12
button, but this depends on what web browser you're using.
Frequenty Asked Questions
Can I Initialize My Own Array Of People As Default Values?
Yes, if you want to initialize your own array of people as the default values of the form, you can do so using something like the following.
1const startingPeople = [{ 2 first: "First Name", 3 last: "Last Name", 4 age: 26 5}, { 6 first: "First Name #2", 7 last: "Last Name #2", 8 age: 21 9}] 10 11... 12<Formik 13 initialValues={{ 14 people: startingPeople 15 }} 16 ... 17> 18 ... 19</Formik>
Conclusion
That's all! I wanted to show you how to make a very simple form with dynamic fields and I hope this guide has helped you achieve that goal!
I also have a couple open source websites that utilize dynamic fields inside of forms using React, Formik, and TypeScript listed below if you want to check them out!
About Christian Deacon
Hi! I am the founder and CEO of Deaconn. I specialize in software and network engineering. I also love system administration and I'm a huge fan of Linux! I contribute to a few open source projects as well!