組み込みブラウザの<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>

詳細については、以下の例を参照してください。

プロパティ

<select>は、共通要素のプロパティをすべてサポートしています。

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

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

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

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

これらの<select>プロパティは、非制御および制御の両方のセレクトボックスに関連します。

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

注意事項

  • HTMLとは異なり、selected属性を<option>に渡すことはサポートされていません。代わりに、制御されていないセレクトボックスには<select defaultValue>を使用し、制御されたセレクトボックスには<select value>を使用してください。
  • セレクトボックスが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>
  );
}


セレクトボックスのラベル付け

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

<select><label>にネストできない場合は、同じIDを<select id><label htmlFor>に渡して関連付けます。1つのコンポーネントの複数のインスタンス間の競合を避けるために、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属性を渡すことはサポートされていません。


複数選択の有効化

multiple={true}<select>に渡して、ユーザーが複数のオプションを選択できるようにします。その場合、最初に選択したオプションを選択するために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">を使用してください。


ステート変数でセレクトボックスを制御する

<select /> のようなセレクトボックスは、非制御です。初期選択値を渡す場合、例えば <select defaultValue="orange" /> のようにしても、JSXは初期値を指定するだけで、現在の値を指定するわけではありません。

制御されたセレクトボックスをレンダリングするには、value プロパティを渡します。Reactは、セレクトボックスが常に渡されたvalue を持つように強制します。通常、セレクトボックスは、ステート変数を宣言することで制御します:

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を渡して制御する場合、渡した値を常に持つように強制します。そのため、ステート変数をvalueとして渡しても、onChangeイベントハンドラでそのステート変数を同期的に更新するのを忘れると、Reactはすべてのキーストローク後にセレクトボックスを、指定したvalueに戻します。

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