Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Implementing a Radio List with Text Input in React

Jun 15, 2020 • 6 Minute Read

Introduction

Forms seem pretty easy to build in plain HTML, but when it comes to JavaScript frameworks like React, it can be a bit tricky. React expects you to manage the form data yourself using state, instead of relying on the DOM to maintain the form data.

When you have a fixed set of input fields, it is easy to add them in your component; but dynamic fields can be challenging as you need to maintain the fields in the state. In this guide, you will learn how to create a dynamic radio list using a text input.

Start With The Component Class

Since all the form data needs to be handled by state, create properties in state to store the text input and radio list value. Also, initialize an empty array in state to store the radio options.

      class App extends Component {
  state = {
    textValue: "",
    checkedOptionValue: "",
    options: [],
  };
}
    

Create the text input to add the radio options along with an Add button.

      class App extends Component {
  state = {
    textValue: "",
    checkedOptionValue: "",
    options: [],
  };

  render() {
    return (
      <div className="App">
        <input
          type="text"
          value={textValue}
          onChange={(e) => this.setState({ textValue: e.target.value })}
        />
        <button onClick={this.handleOptionAdd}>Add</button>
      </div>
    );
  }
}
    

When the user clicks on the Add button, push the text value into the options state. Only push the text value if its length is greater than zero; otherwise, you will end up with radio options with empty values. Another thing to note here is that you need to store the option as an object of label and value.

      handleOptionAdd = () => {
  const { options, textValue } = this.state;
  if (textValue.trim().length === 0) return;
  this.setState({ textValue: "" });
  this.setState({
    options: [
      ...options,
      {
        label: textValue,
        value: textValue.toLowerCase().replace(" ", "-"),
      },
    ],
  });
};
    

Rendering the Radio List

To render the radio list, use the map() method to iterate over the options state array. Ensure that all the radio inputs have the same name prop so that the user can only check one radio input.

      const { options, checkedOptionValue } = this.state;
//
{
  options.map((option) => (
    <div>
      <input
        type="radio"
        name="dynamic-radio"
        value={option.value}
        checked={checkedOptionValue === option.value}
        onChange={this.handleRadioChange}
      />
      <label>{option.label}</label>
    </div>
  ));
}
    

Complete Component Code

Check out the entire code for the component in this section.

      import React, { Component } from "react";
import "./styles.css";

class App extends Component {
  state = {
    textValue: "",
    checkedOptionValue: "",
    options: [],
  };

  handleOptionAdd = () => {
    const { options, textValue } = this.state;
    this.setState({ textValue: "" });
    this.setState({
      options: [
        ...options,
        {
          label: textValue,
          value: textValue.toLowerCase().replace(" ", "-"),
        },
      ],
    });
  };

  handleRadioChange = (e) =>
    this.setState({ checkedOptionValue: e.target.value });

  render() {
    const { options, textValue, checkedOptionValue } = this.state;
    return (
      <div className="App">
        <input
          type="text"
          value={textValue}
          onChange={(e) => this.setState({ textValue: e.target.value })}
        />
        <button onClick={this.handleOptionAdd}>Add</button>

        <div>
          {options.map((option) => (
            <div>
              <input
                type="radio"
                name="dynamic-radio"
                value={option.value}
                checked={checkedOptionValue === option.value}
                onChange={this.handleRadioChange}
              />
              <label>{option.label}</label>
            </div>
          ))}
        </div>
      </div>
    );
  }
}

export default App;
    

Implementation Using Hooks

You can implement the same thing using the useState hook in a functional component. Store the options, textValue, and radioValue in separate state variables, and the rest of the component works similarly to the class component.

      import React, { useState } from "react";
import "./styles.css";

function App() {
  const [options, setOptions] = useState([]);

  const [textValue, setTextValue] = useState("");

  const [radioValue, setRadioValue] = useState("");

  const handleOptionAdd = () => {
    if (textValue.trim().length === 0) return;
    setTextValue("");
    setOptions([
      ...options,
      { label: textValue, value: textValue.toLowerCase().replace(" ", "-") },
    ]);
  };

  return (
    <div className="App">
      <input
        type="text"
        value={textValue}
        onChange={(e) => setTextValue(e.target.value)}
      />
      <button onClick={handleOptionAdd}>Add</button>

      <div>
        {options.map((option) => (
          <div>
            <input
              type="radio"
              name="dynamic-radio"
              value={option.value}
              checked={radioValue === option.value}
              onChange={(e) => setRadioValue(e.target.value)}
            />
            <label>{option.label}</label>
          </div>
        ))}
      </div>
    </div>
  );
}

export default App;
    

Conclusion

It is vital when building forms in React that you think in terms of state and how to manage the form data using state. Relying on the DOM to handle the form data can lead to unpredictable results, making the code difficult to test. Handling the radio list in React is a bit different from what you usually do in HTML, but it gets easier to set up in React once you understand how to deal with values in the state.