Working with forms and form elements when developing with React can be complex because HTML form elements behave somewhat differently in React than other DOM elements.

Learn how to work with forms and form elements such as checkboxes, textareas, and single-line text inputs.

Managing Input Fields in Forms

In React, managing an input field in a form is often accomplished by creating a state and binding it to the input field.

For instance:

        function App() {

const [firstName, setFirstName] = React.useState('');

function handleFirstNameChange(event) {
setFirstName( event.target.value )
}

return (
<form>
<input type='text' placeholder='First Name' onInput={handleFirstNameChange} />
</form>
)
}

Above we have a firstName state, an onInput event, and a handleChange handler. The handleChange function runs on every keystroke to update the firstName state.

This approach may be ideal when working with one input field, but creating different states and handler functions for each input element would become repetitive when working with multiple input fields.

To avoid writing repetitive and redundant code in such situations, give each input field a distinct name, set an object as the initial state value of your form, and then fill the object with properties with the same names as the input fields.

For example:

        function App() {

const [formData, setFormData] = React.useState(
{
firstName: '',
lastName: ''
}
);

return (
<form>
<input type='text' placeholder='First Name' name='firstName' />
<input type='text' placeholder='Last Name' name='lastName' />
</form>
)
}

The formData will serve as the state variable to manage and update all input fields inside the form. Ensure the names of the properties in the state object are identical to the input elements’ names.

To update the state with the input data, add an onInput event listener to the input element, then call your created handler function.

For example:

        function App() {

const [formData, setFormData] = React.useState(
{
firstName: '',
lastName: ''
}
);

function handleChange(event) {
setFormData( (prevState) => {
return {
...prevState,
[event.target.name]: event.target.value
}
})
}

return (
<form>
<input
type='text'
placeholder='First Name'
name='firstName'
onInput={handleChange}
/>
<input
type='text'
placeholder='Last Name'
name='lastName'
onInput={handleChange}
/>
</form>
)
}

The code block above used an onInput event and a handler function, handleFirstNameChange. This handleFirstNameChange function will update the state properties when called. The values of the state properties will be the same as those of their corresponding input elements.

Converting Your Inputs Into Controlled Components

When an HTML form submits, its default behavior is to navigate to a new page in the browser. This behavior is inconvenient in some situations, like when you want to validate the data entered into a form. In most cases, you will find it more suitable to have a JavaScript function with access to the information entered into the form. This can be easily achieved in React using controlled components.

With index.html files, form elements retain track of their state and modify it in response to a user’s input. With React, the set state function modifies a dynamic state stored in the component's state property. You can combine the two states by making the React state the single source of truth. This way, the component that creates a form controls what happens when a user enters data. Input form elements with values that React controls are called controlled components or controlled inputs.

To make use of controlled inputs in your React application, add a value prop to your input element:

        function App() {

const [formData, setFormData] = React.useState(
{
firstName: '',
lastName: ''
}
);

function handleChange(event) {
setFormData( (prevState) => {
return {
...prevState,
[event.target.name]: event.target.value
}
})
}

return (
<form>
<input
type='text'
placeholder='First Name'
name='firstName'
onInput={handleChange}
value={formData.firstName}
/>
<input
type='text'
placeholder='Last Name'
name='lastName'
onInput={handleChange}
value={formData.lastName}
/>
</form>
)
}

The value attributes of the input elements are now set to be the value of corresponding state properties. The value of the input is always determined by the state when using a controlled component.

Handling the Textarea Input Element

The textarea element is like any regular input element but holds multi-line inputs. It is useful when passing information that requires more than a single line.

In an index.html file, the textarea tag element determines its value by its children, as seen in the code block below:

        <textarea>
Hello, How are you?
</textarea>

With React, to use the textarea element, you can create an input element with the type textarea.

Like so:

        function App() {

return (
<form>
<input type='textarea' name='message'/>
</form>
)
}

An alternative to using textarea as an input type is to use the textarea element tag in place of the input type tag, as seen below:

        function App() {

return (
<form>
<textarea
name='message'
value='Hello, How are you?'
/>
</form>
)
}

The textarea tag has a value attribute that holds the user's information entered into the textarea element. This makes it work like a default React input element.

Working With React’s Checkbox Input Element

Things are a little different when working with checkbox inputs. The input field of the type checkbox does not have a value attribute. However, it has a checked attribute. This checked attribute differs from a value attribute by requiring a boolean value to determine whether the box is checked or unchecked.

For example:

        function App() {

return (
<form>
<input type='checkbox' id='joining' name='join' />
<label htmlFor='joining'>Will you like to join our team?</label>
</form>
)
}

The label element refers to the ID of the input element using the htmlFor attribute. This htmlFor attribute takes in the ID of the input element—in this case, joining. When creating an HTML form, the htmlFor attribute represents the for attribute.

The checkbox is better used as a controlled input. You can achieve this by creating a state and assigning it the initial boolean value of true or false.

You should include two props on the checkbox input element: a checked property and an onChange event with a handler function that will determine the state's value using the setIsChecked() function.

For example:

        function App() {

const [isChecked, setIsChecked] = React.useState(false);

function handleChange() {
setIsChecked( (prevState) => !prevState )
}

return (
<form>
<input
type='checkbox'
id='joining'
name='join'
checked={isChecked}
onChange={handleChange}
/>
<label htmlFor='joining'>Will you like to join our team?</label>
</form>
)
}

This code block generates an isChecked state, and sets its initial value to false. It sets the value of isChecked to the checked attribute in the input element. The handleChange function will fire and change the state value of isChecked to its opposite whenever you click on the checkbox.

A form element may likely contain multiple input elements of different types, such as checkboxes, text, etc.

In such cases, you can handle them in a similar way to how you handled multiple input elements of the same type.

Here’s an example:

        function App() {

let[formData, setFormData] = React.useState(
{
firstName: ''
join: true,
}
);

function handleChange(event) {

const {name, value, type, checked} = event.target;

setFormData( (prevState) => {
return {
...prevState,
[name]: type === checkbox ? checked : value
}
})
}

return (
<form>
<input
type='text'
placeholder='First Name'
name='firstName'
onInput={handleChange}
value={formData.firstName}
/>
<input
type='checkbox'
id='joining'
name='join'
checked={formData.join}
onChange={handleChange}
/>
<label htmlFor='joining'>Will you like to join our team?</label>
</form>
)
}

Note that in the handleChange function, setFormData uses a ternary operator to assign the value of the checked property to the state properties if the target input type is a checkbox. If not, it assigns the values of the value attribute.

Now You Can Handle React Forms

You learned how to work with forms in React using different form input elements here. You also learned how to apply controlled inputs to your form elements by adding a value prop or checked prop when working with checkboxes.

Efficient handling of React form input elements will improve the performance of your React application, resulting in a better all-around user experience.