Awesome Dynamic Forms in React

Celestino Salim
Nov 30, 2018 · 5 min read

React is an amazing Javascript Library that is perfect for building user interfaces. One of the components that has always caught my attention is the Form. A few weeks ago I was creating an app and I got stuck with the form. The app was a school with different cohorts. Each cohort has many students and I needed a form that on submit would add all these students to the cohort. I built the app but i was having an issue. The issue was the form component that I created had only one student that could be submitted. Here is where react gets tricky. I needed to make this form dynamic in order to give the user of the app the ability to add as many students as they want.

Before getting into dynamic forms, lets recreate the static form so we can see the difference between one and another.

Static Form

Steps to Static Form

In the above video, I’ve started an example react app from 0, connected the form to the app, and then started to build the controlled form while following the thinking in react, steps.

Inside of the component StaticForm we need an initial State with three keys {cohort: “, name: “, age:”}.

Initial State

Then in our render method we have as a return value a single JSX element which is our <form> and inside that form we have our input fields. On each input field we need a type, a name, and an onChange event that we’re gonna user later to control what the user types called(validations).

input field for static form

The onChange event is triggered every time that we type something in our form. We are going to use the value of the input field and we’re gonna set this to state and the way of doing this is Computed Property Names:

Computed property Name: [] :

At this point our Static Form is almost done. All we have to do now is a Submit handler, which is gonna live in our parent component and is going to be passed down as props to then be invoked(object) in an onSubmit event attached to the <form> JSX element. Do not put your handler to the submit input field or button because then this event is gonna pass the state(obj) to the parent component.

onSubmit event

Finally in our submit handler method we can do whatever we want with that object. In this case, we are just console logging the obj.

submit handler method.

The final result is a controlled Static form with 3 input fields.

Controlled Static Form.

Dynamic Form

Steps to Dynamic Form (using dataset & className)

There’s another way:

Dynamic Form 2

Now for our dynamic form, things change in our initial state. Instead of having empty strings as the values we’re gonna add a key pointing to an array of objects.

Initial State of a Dynamic Form

Then in our render method, the return value is gonna be different too. We no longer need three input fields now it is just going be just one, which is the cohort:

Return Value (Dynamic Form)

We can see that our input field for cohort remains the same since this field will be static, but now we added a button that onClick event is gonna do exactly what it says, “Add New Student”. Then we submit a method that is being invoked this .studentsToAdd() right before our submit.

Let's break it down:


The button to add a new student is setting the state to a copy of the current state with the spread operator and then adding a new object with two keys {name: “”, age: “”}.

Then in the next line of code we have a method called studentsToAdd():

StudentsToAdd Function

This function is returning a div with two input fields both of them point to the same onChange event function and are passing up the index of the “student”.

onChange handleStudentChange Function

Finally, we map through our state and check if the index that we’re getting (idx) passed is not equal to the idx of our mapped array. Then we return the student else return copy of the student state, including the new values, to after set the state.

The rest of our functions remain the same including our submit handler:

submit handler method.

The end result of our form:

Dynamic Form Result.