Creating a radio input component with React.js

getpiggybank.com mobile dev

Let’s just get it out of the way. React is hawt. Still. This made us skeptical to try it, but since being released only two years ago, the front-end framework from Facebook has been adopted by tech monsters including Dropbox, Instagram, Netflix, and Reddit, among many others. I had never used it before working on the front-end of Piggybank, but today I would be hesitant to commit to another approach.

In this post I’ll be detailing how we took care of a relatively simple feature, a set of radio form inputs. There are many ways to handle a form field like this, and this isn’t meant to be an end-all guide to radio inputs in React. This is just our approach.

First off, we had to really look at what is required of a radio set component, and why we even make the radio set it’s own component.

Radio form inputs allow you to select only one option of many, grouped in a set by the `name` attribute. If you select another option in the same set, your first option will be deselected. In the example above we would only be able to select ‘Option A’ or ‘Option B’, not both.

We make this it’s own component so we can include it in any part of our app without having to copy/paste code around. Let’s look at React component with a vanilla HTML implementation of the example above.

var RadioSet = React.createClass({
  render: function () {
    return (
      <fieldset>
        <input id="optionA" name="group" type="radio" value="A" />
        <label for="optionA">Option A</label>
        <input id="optionB" name="group" type="radio" value="B" />
        <label for="optionB">Option B</label>
      </fieldset>
    );
  }
});

module.exports = RadioSet;

Pretty simple, two radio inputs with a label for each, grouped by a fieldset element. That would have worked great if we only used the exact same setup everywhere in our app, but as soon as we needed more or different radio options, we would have needed another separate component. So we looked at how we could give the component some data and make it reusable.

var RadioSet = React.createClass({
  render: function () {
    return (
      <fieldset className="RadioSet">
        <input type="radio"
               id={this.props.name1}
               name={this.props.group} 
               value={this.props.value1} />
        <label for={this.props.name1}>{this.props.title1}</label>
        <br />
        <input type="radio"
               id={this.props.name2}
               name={this.props.group} 
               value={this.props.value2} />
        <label for={this.props.name2}>{this.props.title2}</label>
      </fieldset>
    );
  }
});

module.exports = RadioSet;

In the example above we set the input attributes by setting component props. This would be utilized by giving our component props now like so:

<RadioSet group=”radiogroup”
          label1=”optionA”
	  value1=”A”
	  title1=”Option A”
          label2=”optionB”
          value2=”B”
          title2=”Option B” />

That’s quite a bit better. We could now use the component in different parts of the app by simply giving it different props. Except we still couldn’t use more than two radio inputs, or start with a default option selected. Plus our code isn’t very DRY, since the inputs are essentially identical with different props. So we decided to pass it an array of button data, looping through to create as many buttons as needed.

var RadioSet = React.createClass({
  render: function () {
    var self = this;
    return (
      <fieldset className="RadioSet">
        {this.props.radios.map(function(radio, i){
          return (
            <input type="radio"
                   id={‘option’+i}
                   name={self.props.group} 
                   value={radio.value} 
                   defaultChecked={radio.checked} />
            <label for={‘option’+i}>{radio.title}</label>
	    <br />
	  )
	})}
      </fieldset>
    );
  }
});

module.exports = RadioSet;

And then utilize it in our AddFamilyMember component like so:

<RadioSet group=”permission”
	  radios={[
            {
              label: "Parent",
              value: “1”,
              checked: false
            },
            {
              label: "Child",
              value: “0”,
              checked: true
            }
          ]} />

That’s a much cleaner way to create as many radios as needed, making the component capable of use for almost any scenario we could need in the app. To create more we can just add more data to our array, and using flexbox, we don’t have to change anything in our styles to accomodate it.

<RadioSet group=”permission”
          radios={[
            {
              label: "Parent",
              value: “2”,
              checked: false
            },
            {
              label: "Child",
              value: “1”,
              checked: true
            },
            {
              label: "Other",
              value: “0”,
              checked: false
            }
          ]} />

So far this has worked like a charm for us here at Piggybank, but we’re always looking to do things better. What did you like or dislike about our solution? How do you think we could improve? Feel free to email any comments or suggestions to me at adam@getpiggybank.com. Visit getpiggybank.com for more information.