Forms in React is quite different from Vanilla JavaScript.
Instead of waiting at the end to gather all of the information, we constantly keep track of all information in state
.
Therefore, we can have the most updated version of what user is typing into the form.
We accomplish this by doing the following two steps:
For functional components, we use React Hook’s useState to control input.
Step 1
To start, let’s define a functional component and create a form with Name input and a submit button.
import React, { useState } from 'react';
const App = () => {
return (
<div>
<form className='form'>
<div className='form-control'>
<label htmlFor='firstName'>Name: </label>
<input
type='text'
id='firstName'
name='firstName'
/>
</div>
<button type='submit'>Add person</button>
</form>
</div>
);
};
export default App;
Step 2: Set up state value
const [firstName, setFirstName] = useState('');
Step 3: Add 2 attributes in the input: value
and onChange
event listener
onChange event listener will fire the call back event listener every time we type the input
<input
type='text'
id='firstName'
name='firstName'
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
Step 4: Submitting forms To submit the form in React, we can do the following steps:
button
or input
as our submit buttons<button>Submit</button>
or
<input type="submit" value="Submit" />
<form>
or<form onSubmit={handleSubmit}></form>
<button type="submit" onClick={handleSubmit}>Submit</button>
const handleSubmit = (e) => {
e.preventDefault();
alert('You have submitted');
}
Putting it all together
import React, { useState } from 'react';
const App = () => {
const [firstName, setFirstName] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
alert('You have submitted');
}
return (
<div>
<form className='form' onSubmit={handleSubmit}>
<div className='form-control'>
<label htmlFor='firstName'>Name: </label>
<input
type='text'
id='firstName'
name='firstName'
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
</div>
<button type='submit'>Add person</button>
</form>
</div>
);
};
export default App;
Forms in Class Components are slightly different from Functional Components.
Here are steps to take an input element and transform it into a controlled component.
Step 1
To start, let’s define a class component, constructor, props, super props, state and render method.
import React from "react"
class App extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<input />
)
}
}
export default App
Step 2
To turn an input field into a Controlled Component, we need to tie its value to the component state.
this.state = { value: ''}
Step 3
Next, we need to declare an event handler that will update the state input value whenever the form input value is changed.
The event.target.value
attribute represents the new value of the inputs after it’s been changed:
handleChange(event) {
this.setState({
value: event.target.value
})
}
Step 4
We need to bind the event handler to the component instance and also declare the initial state value:
constructor(props){
super(props)
this.state = {value: ''}
this.handleChange = this.handleChange.bind(this)
}
Step 5
We then must attach the event handler to the <input>
element in render method and set the input value equal to the state input value:
render(){
return (
<input
type = "text"
value = {this.state.value}
onChange = {this.handleChange}
/>
)
}
Putting it all together
import React from "react"
class App extends React.Component {
constructor(props) {
super(props)
this.state = {value: ''}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
render() {
return (
<input
type = "text"
value = {this.state.value}
onChange = {this.handleChange}
/>
)
}
}
Example
Here is a simple form with firstName and lastName as input text.
import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {
firstName: "",
lastName: ""
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
render() {
return (
<form>
<input
type="text"
value={this.state.firstName}
name="firstName"
placeholder="First Name"
onChange={this.handleChange}
/>
<br />
<input
type="text"
value={this.state.lastName}
name="lastName"
placeholder="Last Name"
onChange={this.handleChange}
/>
<h2>{this.state.firstName} {this.state.lastName}</h2>
</form>
)
}
}
export default App
To submit the form, we can do the following steps:
Step 1: Use button or input as our submit buttons
<button>Submit</button>
or
<input type="submit" value="Submit" />
Step 2: Add an onSubmit event handler in <form>
<form onSubmit={this.handleSubmit}></form>
Step 3: Add handleSubmit function
handleSubmit(event) {
e.preventDefault();
alert('You have submitted: ' + this.state.value);
}
and bind handleSubmit:
this.handleSubmit = this.handleSubmit.bind(this);
In React, textarea
is a self-closing element, and we can use value
attribute.
Therefore, we can update the value
in the textarea by updating state
.
<textarea value={}/>
class App extends React.Component {
constructor(props){
super(props)
this.state = {value: 'Write your comment here'}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value})
}
handleSubmit(event) {
e.preventDefault();
alert('You have submitted: ' + this.state.value);
}
render(){
return (
<form onSubmit={this.handleSubmit}>
<label>
Comment:
<textarea
value = {this.state.value}
onChange = {this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
)
}
}
The text area starts with some text because this.state.value
is initialized in the constructor
Checkboxes use a checked
property instead of value
in textarea or input.
Checkbox is either checked or not checked.
Step 1
Firstly, we add a checked
property and it is determined by a Boolean (true or false) in state.
We also give it the name as checked
.
<input
type = "checkbox"
name = "checked"
checked = {this.state.checked}
/>
Step 2
Next, we set checked
state as false, so it starts out as being unchecked.
this.state = {checked: false}
Step 3: Add an onChange event handler
<input
type = "checkbox"
name = "checked"
checked = {this.state.checked}
onChange = {this.handleChange}
/>
Step 4: Add handleChange function
handleChange(event) {
this.setState({checked: event.target.checked})
}
and bind handleChange:
this.handleChange = this.handleChange.bind(this)
Putting it all together
class App extends React.Component{
constructor(props) {
super(props)
this.state = {checked: false}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event){
this.setState({value: event.target.value})
}
handleSubmit(event) {
e.preventDefault();
alert('You have submitted: ' + this.state.value);
}
render(){
return (
<form onSubmit={this.handleSubmit}>
<input
type = "checkbox"
name = "checked"
checked = {this.state.checked}
onChange = {this.handleChange}
/>
<input type="submit" value="Submit" />
</form>
)
}
}
Radio button is the combination of input type text and checkbox. It uses both value
and checked
property.
Example: Creating 2 radio buttons for Male and Female options
Step 1: We set type as radio
, add name
and value
property.
<form>
<label>
<input
type="radio"
name="gender"
value="male"
/> Male
</label>
<br />
<label>
<input
type="radio"
name="gender"
value="female"
/> Female
</label>
</form>
Step 2
Next, we set gender
state as an empty string.
this.state = {gender: ""}
Step 3: Add an onChange event handler
onChange={this.handleChange}
Step 4: Add handleChange function
handleChange(event) {
this.setState({checked: event.target.checked})
}
and bind handleChange:
this.handleChange = this.handleChange.bind(this)
Step 5
For Male radio button, we set it’s checked if this.state.gender === "male"
<input
type="radio"
name="gender"
value="male"
checked={this.state.gender === "male"}
onChange={this.handleChange}
/>
Similarly, for Female radio button, we set it’s checked if this.state.gender === "female"
<input
type="radio"
name="gender"
value="male"
checked={this.state.gender === "female"}
onChange={this.handleChange}
/>
Putting it all together
class App extends React.Component{
constructor(props) {
super(props)
this.state = {checked: false}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({checked: event.target.checked})
}
handleSubmit(event) {
e.preventDefault();
alert('You have submitted: ' + this.state.value);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
<input
type="radio"
name="gender"
value="male"
checked={this.state.gender === "male"}
onChange={this.handleChange}
/> Male
</label>
<br />
<label>
<input
type="radio"
name="gender"
value="female"
checked={this.state.gender === "female"}
onChange={this.handleChange}
/> Female
</label>
<input type="submit" value="Submit" />
</form>
)
}
}
In HTML, <select>
creates a drop-down list
<select>
<option selected value="apple">apple</option>
<option value="banana">banana</option>
<option value="mango">mango</option>
<option value="strawberry">strawberry</option>
</select>
In React, we use value
attribute on the root select
tag, instead of selected
attribute.
Step 1:
value
, onChange
handler, and name
in select
.value
.<select
value={this.state.value}
onChange={this.handleChange}
name="fruit"
>
<option selected value="apple">apple</option>
<option value="banana">banana</option>
<option value="mango">mango</option>
<option value="strawberry">strawberry</option>
</select>
Step 2: Next, we set which fruit is chosen at first.
this.state = {value: "apple"}
Step 3:
Add handleChange function
handleChange(event) {
this.setState({checked: event.target.checked})
}
and bind handleChange:
this.handleChange = this.handleChange.bind(this)
Putting it all together
class App extends React.Component {
constructor(props){
super(props)
this.state = {value: "apple"}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event){
this.setState({value: event.target.value})
}
handleSubmit(event) {
e.preventDefault();
alert('You have submitted: ' + this.state.value);
}
render(){
return (
<form onSubmit={this.handleSubmit}>
<label>Favorite Fruit:</label>
<select
value={this.state.value}
onChange={this.handleChange}
name="fruit"
>
<option value="apple">apple</option>
<option value="banana">banana</option>
<option value="mango">mango</option>
<option value="strawberry">strawberry</option>
</select>
<input type="submit" value="Submit" />
</form>
)
}
}
Select Components can also have their options dynamically generated using the map() method. Example:
class ControlledSelect extends React.Component{
constructor(props) {
super(props)
this.state = {value: "apple"}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({value: event.target.value})
}
render() {
let array = ["apple","banana","mango","strawberry"]
let options = array.map( (item) =>
<option value = {item}>{item}</option>
)
return (
<select value={this.state.value} onChange={this.handleChange}>
{options}
</select>
)
}
}