Dynamic(Reactive) form in React without a library.

Dynamic Input box in react

In this tutorial, we will learn how to make a reactive i.e dynamic input for dynamic form in react like the above image.

Many times we need a form where we have to add input box or any input dynamically based on user input. Today we will make such input box where a user will add and remove input box. Also, this input box will support two-way data binding, so we can fully control them. Such form in angular is called reactive forms. But we will implement it in react without any external library.


Step 1 →

First, create a new react app with create-react-app and remove all useless code in the app.js file inside the src folder.

import React, { Component } from “react”;
class App extends Component {
 render() {
  return (
   <div>
   </div>
  );
 }
}
export default App;

Step 2 →

Now we will need a state which will store all values of all input fields. We will create a property in a state called values which will be an array which will store all values of all input field.

import React, { Component } from “react”;
class App extends Component {
 state = {
 values: [“”]
 };
 render() {
  return (
   <div>
   </div>
  );
 }
}
export default App;

Step 3 →

Now let's create input field, buttons to add, remove input field and submit a form.

import React, { Component } from "react";
class App extends Component {
state = {
values: [""]
};
render() {
return (
<div>
{this.state.values.map((data, index) => {
return (
<div>
<input
type="text"
value={this.state.values[index]}
/>
<button>
Remove
</button>
</div>
);
})}
<br />
<button>Add</button>
<input type="submit" value="submit" />
</div>
);
}
}
export default App;

Here we use a map to create input field and remove button associated to that input field based on state’s values property i.e this.state.values.

Above we are creating Add and submit button outside map as they are not associated with any particular input field.

Step 4 →

Now we will add two-way binding to our input field and print values inside the input field below form.

To do that first add onChange event to an input field.

<input
 type=”text”
 value={this.state.values[index]}
 onChange={e => {
  this.changeHandler(e, index);
 }}
/>

Here we are passing event and index to changeHandler as we need an index of the input field to which we want to change the value.

Now create a method called changeHandler as below

changeHandler = (e, index) => {
 let values = […this.state.values]; 
 values[index] = e.target.value;
 this.setState({
  values: values 
 });
};

Here we accept index which we are passing through the input field.

Inside a method, we first copy the state’s values inside a variable called values.

Then we change the value of the input field whose index is passed to the user’s input.

Then we set state to new values variable which contains updated user input value.

Now we will print user value below submit button using map

<button>Add</button>
<input type=”submit” value=”submit” />
{this.state.values.map(value => {
return <p>{value}</p>;
})}

Complete code until now →

import React, { Component } from "react";
class App extends Component {
state = {
values: [""]
};
changeHandler = (e, index) => {
let values = [...this.state.values];
values[index] = e.target.value;
this.setState({
values: values
});
};
render() {
return (
<div>
{this.state.values.map((data, index) => {
return (
<div>
<input
type="text"
value={this.state.values[index]}
onChange={e => {
this.changeHandler(e, index);
}}
/>
<button>
Remove
</button>
</div>
);
})}
<br />
<button>Add</button>
<input type="submit" value="submit" />
{this.state.values.map(value => {
return
<p>{value}</p>
;
})}
</div>
);
}
}
export default App;

Step 5 →

We have now simple two-way bounded input filed.

Now let's make that add and remove button work

Attach an onClick event to add and remove buttons

<div>
<input
type="text"
value={this.state.values[index]}
onChange={e => {
this.changeHandler(e, index);
}}
/>
<button
onClick={e => {
this.removeHandler(e, index);
}}
>
Remove
</button>
</div>
);
})}
<br />
<button onClick={this.addHandler}>Add</button>

Now create an addHandler method like below

addHandler = () => {
 let values = [...this.state.values];
 values.push("");
 this.setState({
  values: values
 });
};

Here we first copy all state’s value to a variable called values.

Then we push an empty string in that array and set state to new values variable.

Now try clicking on that add button, it should work.

Now create a method called removeHandler like below —

removeHandler = (e, index) => {
 let values = [...this.state.values];
 values.splice(index, 1);
 this.setState({
  values: values
 });
};

Here we take the index of the input field as we want to remove only that input field which user has selected.

create a variable called values which will contain all the state values.

Then remove the value from an array using splice method and pass it index and 1 as we want to remove one element from the array starting from index

Then use setState to set values as new values variable

Below is a complete code →

import React, { Component } from "react";
class App extends Component {
state = {
values: [""]
};
changeHandler = (e, index) => {
let values = [...this.state.values];
values[index] = e.target.value;
this.setState({
values: values
});
};
addHandler = () => {
let values = [...this.state.values];
values.push("");
this.setState({
values: values
});
};
removeHandler = (e, index) => {
let values = [...this.state.values];
values.splice(index, 1);
this.setState({
values: values
});
};
render() {
return (
<div>
{this.state.values.map((data, index) => {
return (
<div>
<input
type="text"
value={this.state.values[index]}
onChange={e => {
this.changeHandler(e, index);
}}
/>
<button
onClick={e => {
this.removeHandler(e, index);
}}
>
Remove
</button>
</div>
);
})}
<br />
<button onClick={this.addHandler}>Add</button>
<input type="submit" value="submit" />
{this.state.values.map(value => {
return <p>{value}</p>;
})}
</div>
);
}
}
export default App;

Hope you have learned how to make dynamic input field and can proceed to make a complete dynamic form with multiple dynamic input types.