ブラウザ組み込みの <select> コンポーネントを利用することで、選択肢を含むセレクトボックスをレンダーすることができます。

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

リファレンス

<select>

セレクトボックスを表示するためには、ブラウザ組み込みの <select> コンポーネントをレンダーします。

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

さらに例を見る

Props

<select>一般的な要素の props をすべてサポートしています。

value プロパティを渡すことで、セレクトボックスを制御できます。

  • value: 文字列(または multiple={true} の場合は文字列の配列)。これにより、どのオプションが選択されているかを制御します。すべての value 文字列は、<select> 内にネストされたいくつかの <option>value と一致します。

value を渡す場合は、渡された値を更新する onChange ハンドラも渡す必要があります。

もし <select> を非制御として使用する場合は、代わりに defaultValue プロパティを渡すことができます。

以下の <select> のプロパティは、非制御セレクトボックスと制御されたセレクトボックスの両方に関連します。

  • autoComplete: 文字列。可能な オートコンプリート動作 の 1 つを指定します。
  • autoFocus: ブーリアン。true の場合、React は要素をマウント時にフォーカスします。
  • children: <select><option><optgroup><datalist> コンポーネントを子として受け入れます。許可されたコンポーネントの 1 つを最終的にレンダーする場合に限り、独自のコンポーネントを渡すこともできます。<option> タグを最終的にレンダーする独自のコンポーネントを渡す場合、レンダーする各 <option> には value が必要です。
  • disabled: ブーリアン。true の場合、セレクトボックスはインタラクティブではなくなり、薄暗く表示されます。
  • form: ブーリアン。このセレクトボックスが属する <form> 要素の id を指定します。省略した場合、最も近い親フォームが対象となります。
  • multiple: ブーリアン。true の場合、ブラウザで複数選択が可能になります。
  • name: 文字列。フォームとともに送信されるこの選択ボックスの名前を指定します。
  • onChange: Event ハンドラ関数。制御されたセレクトボックスでは必要です。ユーザが別のオプションを選択したときに即座に発火します。ブラウザの input event と似た挙動を示します。
  • onChangeCapture: onChangeキャプチャーフェーズで発火するバージョンです。
  • onInput: Event ハンドラ関数。ユーザによって値が変更されたときに即座に発火します。歴史的な理由から、React では代わりに同様の動作をする onChange を使用するのが慣習となっています。
  • onInputCapture: onInputキャプチャーフェーズで発火するバージョンです。
  • onInvalid: Event ハンドラ関数。フォームの送信時に入力の検証に失敗した場合に発火します。組み込みの invalid イベントとは異なり、React の onInvalid イベントはバブルします。
  • onInvalidCapture: onInvalidキャプチャーフェーズで発火するバージョンです。
  • required: ブーリアン。true の場合、フォームを送信するには値の指定が必要です。
  • size: 数値。multiple={true} の場合, 最初に表示される項目の数を指定します。

注意点

  • HTML とは異なり、<option>selected 属性を渡すことはサポートされていません。代わりに、非制御のセレクトボックスには <select defaultValue> を使用し、制御されたセレクトボックスには <select value> を使用します。
  • セレクトボックスに value プロパティが渡されると、制御されたコンポーネントとして扱われます
  • セレクトボックスは同時に制御されたコンポーネントと非制御コンポーネントにはなれません。
  • セレクトボックスは、ライフタイム中に制御されたコンポーネントから非制御コンポーネント、またはその逆に切り替えることはできません。
  • すべての制御されたセレクトボックスには、そのバッキング値 (backing value) を同期的に更新するための onChange イベントハンドラが必要です。

使用法

選択肢を含むセレクトボックスを表示する

<option> コンポーネントのリストを内部に含む <select> をレンダーして、セレクトボックスを表示します。各 <option> に、フォームとともに送信されるデータを表す value を指定してください。

export default function FruitPicker() {
  return (
    <label>
      Pick a fruit:
      <select name="selectedFruit">
        <option value="apple">Apple</option>
        <option value="banana">Banana</option>
        <option value="orange">Orange</option>
      </select>
    </label>
  );
}


セレクトボックスにラベルを付ける

通常、<label> タグ内に <select> を配置します。これにより、ブラウザに対してこのラベルがそのセレクトボックスに関連付けられていることが伝わります。ユーザがラベルをクリックすると、ブラウザは自動的にセレクトボックスにフォーカスします。これはアクセシビリティの観点からも重要です。ユーザがセレクトボックスにフォーカスすると、スクリーンリーダーがラベルのキャプションを読み上げます。

もし <label> 内に <select> をネストできない場合は、同じ ID を <select id><label htmlFor> に渡すことで関連付けることができます。同一コンポーネントの複数のインスタンス間で競合を避けるために、useId を使用してそのような ID を生成することが推奨されます。

import { useId } from 'react';

export default function Form() {
  const vegetableSelectId = useId();
  return (
    <>
      <label>
        Pick a fruit:
        <select name="selectedFruit">
          <option value="apple">Apple</option>
          <option value="banana">Banana</option>
          <option value="orange">Orange</option>
        </select>
      </label>
      <hr />
      <label htmlFor={vegetableSelectId}>
        Pick a vegetable:
      </label>
      <select id={vegetableSelectId} name="selectedVegetable">
        <option value="cucumber">Cucumber</option>
        <option value="corn">Corn</option>
        <option value="tomato">Tomato</option>
      </select>
    </>
  );
}


デフォルトのオプションを指定する

デフォルトでは、ブラウザはリスト内の最初の <option> を選択します。異なるオプションをデフォルトで選択する場合は、その <option>value<select> 要素の defaultValue として渡します。

export default function FruitPicker() {
  return (
    <label>
      Pick a fruit:
      <select name="selectedFruit" defaultValue="orange">
        <option value="apple">Apple</option>
        <option value="banana">Banana</option>
        <option value="orange">Orange</option>
      </select>
    </label>
  );
}

落とし穴

HTML とは異なり、個々の <option>selected 属性を渡すことはサポートされていません。


複数選択を有効にする

複数のオプションを選択できるようにするには、<select>multiple={true} を渡します。その場合、初期選択オプションを指定するために defaultValue を指定する必要がありますが、defaultValue は配列である必要があります。

export default function FruitPicker() {
  return (
    <label>
      Pick some fruits:
      <select
        name="selectedFruit"
        defaultValue={['orange', 'banana']}
        multiple={true}
      >
        <option value="apple">Apple</option>
        <option value="banana">Banana</option>
        <option value="orange">Orange</option>
      </select>
    </label>
  );
}


フォーム送信時のセレクトボックスの値の読み取り

セレクトボックスを <form> で囲み、その中に <button type="submit"> を配置します。これにより、<form onSubmit> イベントハンドラが呼び出されます。デフォルトでは、ブラウザはフォームデータを現在の URL に送信し、ページを更新します。e.preventDefault() を呼び出すことで、その振る舞いをオーバーライドできます。new FormData(e.target) を使用してフォームデータを読み込みます。

export default function EditPost() {
  function handleSubmit(e) {
    // Prevent the browser from reloading the page
    e.preventDefault();
    // Read the form data
    const form = e.target;
    const formData = new FormData(form);
    // You can pass formData as a fetch body directly:
    fetch('/some-api', { method: form.method, body: formData });
    // You can generate a URL out of it, as the browser does by default:
    console.log(new URLSearchParams(formData).toString());
    // You can work with it as a plain object.
    const formJson = Object.fromEntries(formData.entries());
    console.log(formJson); // (!) This doesn't include multiple select values
    // Or you can get an array of name-value pairs.
    console.log([...formData.entries()]);
  }

  return (
    <form method="post" onSubmit={handleSubmit}>
      <label>
        Pick your favorite fruit:
        <select name="selectedFruit" defaultValue="orange">
          <option value="apple">Apple</option>
          <option value="banana">Banana</option>
          <option value="orange">Orange</option>
        </select>
      </label>
      <label>
        Pick all your favorite vegetables:
        <select
          name="selectedVegetables"
          multiple={true}
          defaultValue={['corn', 'tomato']}
        >
          <option value="cucumber">Cucumber</option>
          <option value="corn">Corn</option>
          <option value="tomato">Tomato</option>
        </select>
      </label>
      <hr />
      <button type="reset">Reset</button>
      <button type="submit">Submit</button>
    </form>
  );
}

補足

<select> に name を指定してください。例えば <select name="selectedFruit" /> のように指定します。指定した name はフォームデータ内のキーとして使用されます。例えば、{ selectedFruit: "orange" } のようになります。

<select multiple={true}> を使用すると、フォームから読み取った FormData には、それぞれ選択された値が個別の名前と値のペアとして含まれます。上記の例のコンソールログをよく確認してください。

落とし穴

デフォルトでは、<form> 内のどんな <button> もフォームを送信します。これは予想外の挙動かもしれません! 独自のカスタム Button React コンポーネントを利用している場合は、<button> の代わりに <button type="button"> を返すように考慮してください。そして、明示的に、フォームを送信することが意図されているボタンには <button type="submit"> を使用してください。


state 変数を使ってセレクトボックスを制御する

<select /> のようなセレクトボックスは 非制御 です。たとえ <select defaultValue="orange" /> のように デフォルトのオプションを指定 しても、JSX は初期値のみを指定しており、現在の値を表しているわけではありません。

**制御されたセレクトボックスをレンダーするには、value プロパティを渡してください。**React はセレクトボックスに常に渡した value を保持します。通常、state 変数を宣言することでセレクトボックスを制御します。

function FruitPicker() {
const [selectedFruit, setSelectedFruit] = useState('orange'); // Declare a state variable...
// ...
return (
<select
value={selectedFruit} // ...force the select's value to match the state variable...
onChange={e => setSelectedFruit(e.target.value)} // ... and update the state variable on any change!
>
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="orange">Orange</option>
</select>
);
}

これは、選択毎に UI の一部を再レンダーしたい場合に便利です。

import { useState } from 'react';

export default function FruitPicker() {
  const [selectedFruit, setSelectedFruit] = useState('orange');
  const [selectedVegs, setSelectedVegs] = useState(['corn', 'tomato']);
  return (
    <>
      <label>
        Pick a fruit:
        <select
          value={selectedFruit}
          onChange={e => setSelectedFruit(e.target.value)}
        >
          <option value="apple">Apple</option>
          <option value="banana">Banana</option>
          <option value="orange">Orange</option>
        </select>
      </label>
      <hr />
      <label>
        Pick all your favorite vegetables:
        <select
          multiple={true}
          value={selectedVegs}
          onChange={e => {
            const options = [...e.target.selectedOptions];
            const values = options.map(option => option.value);
            setSelectedVegs(values);
          }}
        >
          <option value="cucumber">Cucumber</option>
          <option value="corn">Corn</option>
          <option value="tomato">Tomato</option>
        </select>
      </label>
      <hr />
      <p>Your favorite fruit: {selectedFruit}</p>
      <p>Your favorite vegetables: {selectedVegs.join(', ')}</p>
    </>
  );
}

落とし穴

**onChange を指定せずに value を渡すと、オプションを選択することができなくなります。**セレクトボックスに value 渡して制御すると、渡した値が常に強制されることになります。したがって、state 変数を value として渡しても、onChange イベントハンドラ内でその state 変数を同期的に更新するのを忘れた場合、React はキーストローク毎にセレクトボックスを指定した value に戻してしまいます。

HTML とは異なり、個々の <option>selected 属性を渡すことはサポートされていません。