Dropdowns In React 16

How do you use dropdowns in React 16?

Let's answer to this question with a simple example.

We're going to build a React app that creates a form with a payment methods dropdown:

Application screenshot
Figure 1. Our application.

Initially, no payment method will be selected and the Submit button will be disabled - users can't submit a form without selecting a payment method first.

Users can click on the dropdown to select one of the payment methods:

Application screenshot
Figure 2. Our application.

Once the payment method is selected, the Submit button is enabled and users can submit the form:

Application screenshot
Figure 3. Our application.

When you click the Submit button, we'll log selected payment method in JavaScript console:

Application screenshot
Figure 4. Our application.

You can find the full source code in this GitHub repository.

First let's create App component:


import React, { Component } from "react";

class App extends Component {
  state = {
    selectedValue: "noPaymentMethod"
  };

  handleSelectValue = event => {
    this.setState({
      selectedValue: event.target.value
    });
  };

  handleFormSubmit = event => {
    event.preventDefault();

    console.log("You have submitted:", this.state.selectedValue);
  };

  render() {
    return (
      <div className="container">
        <div className="row">
          <div className="col-md-6 offset-md-3 mt-5 mb-5">
            <h2 className="mb-4">Payment</h2>
            <form onSubmit={this.handleFormSubmit}>
              <div className="form-group">
                <label htmlFor="paymentMethod">Payment method</label>
                <select
                  value={this.state.selectedValue}
                  onChange={this.handleSelectValue}
                  className="form-control"
                  id="paymentMethod"
                >
                  <option value="noPaymentMethod">Select payment method</option>
                  <option value="creditCard">Credit Card</option>
                  <option value="debitCard">Debit Card</option>
                  <option value="bankTransfer">Bank Transfer</option>
                </select>
              </div>
              <button
                type="submit"
                className="btn btn-primary"
                disabled={this.state.selectedValue === "noPaymentMethod"}
              >
                Submit
              </button>
            </form>
          </div>
        </div>
      </div>
    );
  }
}

export default App;

Code snippet 1. App.js

Our App component is a stateful component that renders form. Let's take a closer look at it's render method:


render() {
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6 offset-md-3 mt-5 mb-5">
          <h2 className="mb-4">Payment</h2>
          <form onSubmit={this.handleFormSubmit}>
            <div className="form-group">
              <label htmlFor="paymentMethod">Payment method</label>
              <select
                value={this.state.selectedValue}
                onChange={this.handleSelectValue}
                className="form-control"
                id="paymentMethod"
              >
                <option value="noPaymentMethod">Select payment method</option>
                <option value="creditCard">Credit Card</option>
                <option value="debitCard">Debit Card</option>
                <option value="bankTransfer">Bank Transfer</option>
              </select>
            </div>
            <button
              type="submit"
              className="btn btn-primary"
              disabled={this.state.selectedValue === "noPaymentMethod"}
            >
              Submit
            </button>
          </form>
        </div>
      </div>
    </div>
  );
}

Code snippet 2. App.js

Our App component renders form with label, select and button elements. The select element creates our dropdown:


<select
  value={this.state.selectedValue}
  onChange={this.handleSelectValue}
  className="form-control"
  id="paymentMethod"
>
  <option value="noPaymentMethod">Select payment method</option>
  <option value="creditCard">Credit Card</option>
  <option value="debitCard">Debit Card</option>
  <option value="bankTransfer">Bank Transfer</option>
</select>

Code snippet 3. App.js

Our dropdown has four options:

  1. Select payment method
  2. Credit Card
  3. Debit Card
  4. Bank Transfer

Each option is created with option element that gets value prop.

At this point we should ask ourselves two questions:

  1. Which option will be selected initially?
  2. How can a user change selected option?

Let's answer these questions.

Each option in our dropdown represents a state. You can think of a select element as a stateful component. This state is hidden from us and we don't control it. We don't control and we don't know which option is selected. However, if we do need to know which option is selected, then we need to take control over the select element. If you have read my Radio Buttons in React 16 tutorial, then you already know that React gives you an option to create form elements that are controlled by you - they're called Controlled Compponents.

To take control over our select element, we need to do two things.

First, we provide value prop to our select element. This prop tells React which option inside of our select to render. How does it know? Each option element has it's own value prop. If select's value prop matches option's value prop, then React will render that option element.

Second, we prodive onChange prop to our select element. The onChange prop takes a callback function that React will call every time user selects different option.

When we take control over our select element, we take control over it's state and now our App component will own that state and represent it with selectedValue property.

We set the initial state of selectedValue to "noPaymentMethod":


state = {
  selectedValue: "noPaymentMethod"
};

Code snippet 4. App.js

Our App component also declares the handleSelectValue function that updates selectedValue:


handleSelectValue = event => {
  this.setState({
    selectedValue: event.target.value
  });
};

Code snippet 5. App.js

A new value for selectedValue state property comes from the event object that React will pass as a param when it calls the handleSelectValue callback function. The event object has target property that has value property - that's the value that we set for each option element:


<option value="noPaymentMethod">Select payment method</option>
<option value="creditCard">Credit Card</option>
<option value="debitCard">Debit Card</option>
<option value="bankTransfer">Bank Transfer</option>

Code snippet 6. App.js

We pass this.state.selectedValue to the value prop and this.handleSelectValue to the onChange prop of our select element:


<select
  value={this.state.selectedValue}
  onChange={this.handleSelectValue}
  className="form-control"
  id="paymentMethod"
>
  ...
</select>

Code snippet 7. App.js

The idea is that select element always gets it's value from our App component's state. Then user interacts with our dropdown and selects a different option. The select element calls onChange prop which will call our App component's this.handleSelectValue function. The this.handleSelectValue function will update App component's state and React will re-render App component - only this time it will render our select element with a different option selected.

Application screenshot
Figure 5. Option change diagram.

Finally when user submits the form, we want to know which option they selected and log that option in a JavaScript console. For that we declare handleFormSubmit function:


handleFormSubmit = event => {
  event.preventDefault();

  console.log("You have submitted:", this.state.selectedValue);
};

Code snippet 8.

Then we pass handleFormSubmit function to the onSubmit prop of the form element:


<form onSubmit={this.handleFormSubmit}>...</form>

Code snippet 8.

And that's how you create dropdowns in React 16!

Thank you for your attention.

Please take a look at the complete source code on GitHub and the live version of our app.

I hope you've enjoyed this tutorial and I would love to hear your feedback in the comments. You can get in touch with me via Twitter and email.

Artemij Fedosejev

Artemij Fedosejev