React Select Dropdowns

In the last lesson you learned about React Textarea, so you can already control a text box with value and onChange. This lesson handles a <select> dropdown the React way, because it behaves a bit differently than it does in plain HTML.

🤔 Why does a select need special handling?

In plain HTML, a dropdown keeps track of its own choice. React wants to be the one in charge instead.

  • In HTML, you mark the chosen option with the selected attribute, and the browser remembers the pick for you.
  • In React, you don’t want the browser holding that value on its own. You want it in state, where your code can read it and react to it.
  • So React flips it around. The <select> shows whatever your state says, and every change goes back into state first.
  • That two-way tie between state and the box is what we call a controlled component.

📋 A controlled select

A controlled select has two parts. You put value on the <select> tag, and you give it an onChange to catch every pick.

Here a small component lets the user choose a fruit, and the choice lives in state.

import { useState } from "react";
function FruitPicker() {
const [fruit, setFruit] = useState("apple");
return (
<select value={fruit} onChange={(e) => setFruit(e.target.value)}>
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="cherry">Cherry</option>
</select>
);
}

Let’s walk through what makes this controlled.

  • value={fruit} on the <select> tells the dropdown which option to show. It always matches our state.
  • onChange runs the moment the user picks a different option.
  • Inside it, setFruit saves the new pick, so state stays the single source of truth.
  • Notice the chosen option is decided by the <select>, not by any selected on an <option>.

⚠️ value on the select, not selected on the option

This is the one big difference from HTML, so let’s see it clearly. In HTML you mark the option. In React you set the value on the select itself.

Here’s the old HTML habit next to the React way.

// ❌ Wrong - HTML style, putting selected on an option
<select>
<option value="apple">Apple</option>
<option value="banana" selected>Banana</option>
</select>
// ✅ Right - React style, value on the select plus onChange
<select value={fruit} onChange={(e) => setFruit(e.target.value)}>
<option value="apple">Apple</option>
<option value="banana">Banana</option>
</select>

Here’s why the React way wins.

  • With selected on an option, the browser owns the choice and React loses track of it.
  • With value on the <select>, your state decides the choice, so your code always knows the current pick.
  • Change the state and the dropdown updates by itself. That’s the whole point of controlling it.

selected does nothing useful here

If you put selected on an <option> in React, you’ll get a warning and the value won’t stay in sync with your state. Always set the choice with value on the <select> instead.

⌨️ Reading the chosen value

Whenever the user picks an option, React hands your handler an event object. The chosen value sits at e.target.value, the same place you read text inputs from.

Here we read the pick and use it to show a small message.

import { useState } from "react";
function FruitPicker() {
const [fruit, setFruit] = useState("apple");
function handleChange(e) {
setFruit(e.target.value);
}
return (
<div>
<select value={fruit} onChange={handleChange}>
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="cherry">Cherry</option>
</select>
<p>You picked: {fruit}</p>
</div>
);
}

Here’s the flow in order.

  • The user picks an option, so onChange fires.
  • e.target is the <select> element, and e.target.value is the value of the option they chose.
  • setFruit saves that value into state.
  • React re-renders, the dropdown shows the new pick, and the <p> updates too.

Output

(user picks "Banana")
You picked: banana

🗺️ Rendering options from an array

Typing each <option> by hand is fine for three choices. But real lists, like countries or cities, come from data. So you build the options with map, the same way you’d render any list.

Here we keep the choices in an array and turn each one into an option.

import { useState } from "react";
function CityPicker() {
const cities = ["London", "Tokyo", "Mumbai", "Berlin"];
const [city, setCity] = useState("London");
return (
<select value={city} onChange={(e) => setCity(e.target.value)}>
{cities.map((name) => (
<option key={name} value={name}>
{name}
</option>
))}
</select>
);
}

A few things to notice in that map.

  • cities.map(...) walks the array and gives back one <option> per item.
  • Each option needs a key, just like any mapped list, so React can tell them apart.
  • We set both value={name} and the text inside, so the saved value matches what the user sees.
  • The <select> still controls the choice with value={city}. The data only fills in the options.

🏷️ Adding a placeholder option

Often you want the dropdown to start on something like “Choose a city” instead of a real pick. You add a disabled first option and start your state empty.

Here the first option acts as a placeholder that can’t be re-selected.

function CityPicker() {
const cities = ["London", "Tokyo", "Mumbai"];
const [city, setCity] = useState("");
return (
<select value={city} onChange={(e) => setCity(e.target.value)}>
<option value="" disabled>
Choose a city
</option>
{cities.map((name) => (
<option key={name} value={name}>
{name}
</option>
))}
</select>
);
}

Here’s how the placeholder works.

  • State starts as "", so the empty-valued option shows first.
  • That first option has disabled, so once the user picks a real city, they can’t go back to the prompt.
  • The moment they pick a city, state updates and the dropdown shows their choice.

Match the empty value

For the placeholder to show at the start, the option’s value must match your starting state. An empty string in both, value="" and useState(""), is the easy way to line them up.

🔢 A quick word on multiple select

A dropdown can also let the user pick more than one option at once. You turn it on with the multiple attribute, and then the value becomes an array.

Here’s the shape of a multi-select, just so you’ve seen it.

const [picked, setPicked] = useState([]);
<select
multiple
value={picked}
onChange={(e) =>
setPicked(Array.from(e.target.selectedOptions, (opt) => opt.value))
}
>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>;

The key differences to remember.

  • With multiple, the state holds an array of values, not a single string.
  • You can’t just read e.target.value anymore. You read e.target.selectedOptions and pull each value out.
  • For most forms a single-choice dropdown is what you need, so reach for multi-select only when the task really calls for it.

🧩 What You’ve Learned

  • ✅ A <select> in React is a controlled component, with the choice held in state
  • ✅ You set the chosen option with value on the <select>, not selected on an <option>
  • onChange fires when the user picks, and the choice is at e.target.value
  • ✅ Save that value into state with a setter, so state and the dropdown stay in sync
  • ✅ Build options from an array with map, giving each <option> a key
  • ✅ A disabled empty-valued option acts as a placeholder when state starts as ""
  • ✅ A multiple select holds an array of values, read from e.target.selectedOptions

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    In React, how do you set which option is chosen in a select?

    Why: A controlled select sets its choice with value on the <select> itself, plus an onChange to update state. The selected attribute is the HTML way and does not stay in sync with React state.

  2. 2

    Inside the select's onChange, how do you read the option the user picked?

    Why: For a single-choice select, e.target is the select element and e.target.value is the value of the chosen option. You usually save it into state with a setter.

  3. 3

    When you render <option> elements from an array with map, what must each option have?

    Why: Like any mapped list in React, each <option> needs a unique key prop so React can tell the items apart when the list changes.

  4. 4

    How do you make the first option act as a placeholder like 'Choose a city'?

    Why: A first <option> with value empty and disabled shows as the prompt when state starts as empty. Because it is disabled, the user can't return to it after picking a real choice.

🚀 What’s Next?

Now you can handle a dropdown the React way, control it with value, and read the pick from e.target.value. Next we’ll look at another way to let users choose, this time picking one option from a small set with radio buttons.

React Radio Buttons

Share & Connect