<select>
ブラウザ組み込みの <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
プロパティを渡すことで、セレクトボックスを制御されたコンポーネント (controlled component) にできます。
value
: 文字列(またはmultiple={true}
の場合は文字列の配列)。どのオプションが選択されているかを制御します。それぞれの value 文字列は、<select>
内にネストされたいずれかの<option>
のvalue
と一致します。
value
を渡す場合は、渡された値を更新する onChange
ハンドラも渡す必要があります。
もし <select>
を非制御コンポーネント (uncontrolled component) として使用する場合は、代わりに defaultValue
プロパティを渡すことができます。
defaultValue
: 文字列(またはmultiple={true}
の場合は文字列の配列)。デフォルトのオプションを指定 します。
以下の <select>
の props は、非制御セレクトボックスと制御されたセレクトボックスの両方で用いられます。
autoComplete
: 文字列。可能なオートコンプリート動作の 1 つを指定します。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 とは異なり、
<option>
にselected
属性を渡すことはサポートされていません。代わりに、非制御のセレクトボックスには<select defaultValue>
を使用し、制御されたセレクトボックスには<select value>
を使用します。 - セレクトボックスに
value
プロパティが渡されると、制御されたコンポーネントとして扱われます。 - セレクトボックスは制御されたコンポーネントと非制御コンポーネントに同時になることはできません。
- セレクトボックスは、ライフタイム中に制御されたコンポーネントから非制御コンポーネント、またはその逆に切り替えることはできません。
- すべての制御されたセレクトボックスには、制御に使っている state を同期的に更新するための
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>
タグ内に配置します。これにより、ブラウザに対してこのラベルがそのセレクトボックスに関連付けられていることが伝わります。ユーザがラベルをクリックすると、ブラウザは自動的にセレクトボックスにフォーカスします。これはアクセシビリティの観点からも重要です。ユーザがセレクトボックスにフォーカスすると、スクリーンリーダがラベルのキャプションを読み上げます。
もし <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> ); }
複数選択を有効にする
複数のオプションを選択できるようにするには、<select>
に multiple={true}
を渡します。さらに初期選択オプションを指定するために 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> ); }
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> </> ); }