<select>

Renders a dropdown whose selected option React sets with value or defaultValue.

Signature
<select>
  <option value="someOption">Some option</option>
  <option value="otherOption">Other option</option>
</select>

Parameters

ParameterTypeDescription
$valueoptionalstring | string[]Controls which option is selected — an array of strings when multiple is true. Every value string must match the value of some <option> nested inside the <select>. Requires an onChange handler.
$defaultValueoptionalstring | string[]Specifies the initially selected option for uncontrolled select boxes. An array of strings when multiple is true.
$onChangeoptional(event: Event) => voidRequired for controlled select boxes. Fires immediately when the user picks a different option.
$childrenoptionalReactNode<select> accepts <option>, <optgroup> and <datalist> components as children, or custom components that render these. Each rendered <option> must have a value.
$multipleoptionalboolean= falseIf true, the browser allows multiple selection and the value becomes an array of strings.
$nameoptionalstringSpecifies the name for this select box that is submitted with the form.
$sizeoptionalnumberFor multiple={true} selects, specifies the preferred number of initially visible items.
$requiredoptionalboolean= falseIf true, the value must be provided for the form to submit.
$disabledoptionalboolean= falseIf true, the select box will not be interactive and will appear dimmed.
$...propsoptionalHTMLSelectElement props<select> supports all common element props plus autoComplete, autoFocus, form, and the onInput and onInvalid handlers with their capture-phase variants.

Return value

ReactElementRenders a browser <select> element. React sets the selection from value or defaultValue rather than from a selected attribute on any option.

Errors

React logs an error when a select box switches between controlled and uncontrolled, or when a selected attribute is passed to a child <option> instead of using value or defaultValue on the select.

React moves the selection off the options and onto the <select> itself. In plain HTML you mark a child with selected; in React that attribute is unsupported and silently ignored. Instead, pass value for a controlled dropdown or defaultValue for an uncontrolled one, and give every <option> a value so there is something to match against.

When to reach for it

Control the select when the choice drives other UI — filtering a table, showing a dependent second dropdown, enabling a button. Leave it uncontrolled when it is one field among many that you only read on submit.

What trips people up

  • Values are always strings. Selecting the option for the number 2 gives you "2" from event.target.value; convert explicitly if you compare against numbers or use the value as an object key.
  • With multiple, value must be an array of strings, and event.target.value is not that array — read event.target.selectedOptions instead.
  • Setting value to something no option matches leaves the box blank rather than throwing.
  • A dropdown that starts empty needs an explicit placeholder option with value=""; there is no other way to represent "nothing chosen".

Example

Try it yourself
Loading editor…
Loading React…

When to use it

  • Filter a product table by category and re-render the rows on change
  • Preselect a user's saved country in a profile form without controlling it
  • Let a user pick several tags at once with multiple and read the array back

Frequently asked questions

Why is selected not working on my option in React?

React does not support the selected attribute on <option>. Set the initial choice with defaultValue on the <select> for an uncontrolled dropdown, or with value plus onChange for a controlled one. The string you pass must exactly match the value of one of the options, including case.

How do I get all selected values from a multiple select?

Read event.target.selectedOptions and map it to values: Array.from(e.target.selectedOptions, o => o.value). event.target.value gives you only the first selected option. The value prop on a multiple select must likewise be an array of strings rather than a single string.

Why does my select show a blank option when the page loads?

The value or defaultValue you passed does not match any option's value, so the browser has nothing to display — often because the value is a number and option values are strings, or because the options load after the select renders. Convert to a string with String(id), or render a placeholder <option value=""> for the empty state.

More examples

A multiple select with an array value

The list opens with React and Forms highlighted because value is the array ["react", "forms"]. Ctrl- or Cmd-clicking Accessibility renders `Selected: react, forms, a11y`. The crucial line is the handler: e.target.value on a multiple select returns only the first selected option, so the selection has to be rebuilt from e.target.selectedOptions. Passing a bare string to value on a multiple select is the other common error — React expects an array.

Example · jsx
import { useState } from "react";

export default function TagPicker() {
  const [tags, setTags] = useState(["react", "forms"]);

  function handleChange(e) {
    const picked = Array.from(e.target.selectedOptions, (o) => o.value);
    setTags(picked);
  }

  return (
    <div>
      <select multiple size={4} value={tags} onChange={handleChange}>
        <option value="react">React</option>
        <option value="forms">Forms</option>
        <option value="a11y">Accessibility</option>
        <option value="perf">Performance</option>
      </select>
      <p>Selected: {tags.length === 0 ? "(none)" : tags.join(", ")}</p>
    </div>
  );
}

Uncontrolled, grouped, and read from FormData

The dropdown opens on Portugal because defaultValue="pt" matches an option nested two levels down inside an <optgroup> — defaultValue searches all descendants, not just direct children. Submitting renders `country=pt`, or whichever option is chosen. No state or onChange is involved: the DOM holds the selection and FormData reads it once, which is all a plain submit needs.

Example · jsx
import { useState } from "react";

export default function ShipToForm() {
  const [result, setResult] = useState("not submitted");

  function handleSubmit(e) {
    e.preventDefault();
    const data = new FormData(e.currentTarget);
    setResult(`country=${data.get("country")}`);
  }

  return (
    <form onSubmit={handleSubmit}>
      <select name="country" defaultValue="pt" required>
        <optgroup label="Europe">
          <option value="pt">Portugal</option>
          <option value="de">Germany</option>
        </optgroup>
        <optgroup label="Americas">
          <option value="br">Brazil</option>
          <option value="ca">Canada</option>
        </optgroup>
      </select>
      <button type="submit">Ship here</button>
      <p>{result}</p>
    </form>
  );
}

Discussion

  • Be the first to comment on this lesson.