<select>브라우저 내장 <select> 컴포넌트를 사용하면 옵션이 있는 select 박스를 렌더링할 수 있어요.
<select>
<option value="someOption">Some option</option>
<option value="otherOption">Other option</option>
</select>
<select>는 드롭다운 메뉴를 만들어서 사용자가 여러 옵션 중 하나 또는 여러 개를 선택할 수 있게 해줘요. 폼에서 선택지를 제공할 때 가장 많이 사용하는 요소 중 하나예요!
<select>select 박스를 표시하려면, 브라우저 내장 <select> 컴포넌트를 렌더링하세요.
<select>
<option value="someOption">Some option</option>
<option value="otherOption">Other option</option>
</select>
<select>는 모든 공통 요소 props를 지원해요.
value prop을 전달해서 select 박스를 제어할 수 있어요:
value: 문자열이에요 (multiple={true}의 경우 문자열 배열). 어떤 옵션이 선택되었는지 제어해요. 모든 value 문자열은 <select> 안에 중첩된 어떤 <option>의 value와 일치해야 해요.value를 전달하면, 전달된 값을 업데이트하는 onChange 핸들러도 반드시 전달해야 해요.
<select>가 비제어라면, 대신 defaultValue prop을 전달할 수 있어요:
defaultValue: 문자열이에요 (multiple={true}의 경우 문자열 배열). 초기 선택된 옵션을 지정해요.다음 <select> props는 비제어 select 박스와 제어 select 박스 모두에 관련이 있어요:
autoComplete: 문자열이에요. 가능한 자동완성 동작 중 하나를 지정해요.autoFocus: boolean이에요. true면, React가 마운트 시 요소에 포커스할 거예요.children: <select>는 <option>, <optgroup>, <datalist> 컴포넌트를 children으로 받아요. 최종적으로 허용된 컴포넌트 중 하나를 렌더링하는 한 자체 컴포넌트도 전달할 수 있어요. 최종적으로 <option> 태그를 렌더링하는 자체 컴포넌트를 전달하는 경우, 렌더링하는 각 <option>에 value가 있어야 해요.disabled: boolean이에요. true면, select 박스는 인터랙티브하지 않고 흐리게 표시될 거예요.form: 문자열이에요. 이 select 박스가 속한 <form>의 id를 지정해요. 생략되면, 가장 가까운 부모 form이에요.multiple: boolean이에요. true면, 브라우저가 다중 선택을 허용해요.name: 문자열이에요. 폼과 함께 제출되는 이 select 박스의 이름을 지정해요.onChange: 이벤트 핸들러 함수예요. 제어 select 박스에 필수예요. 사용자가 다른 옵션을 선택하면 즉시 실행돼요. 브라우저 input 이벤트처럼 동작해요.onChangeCapture: 캡처 단계에서 실행되는 onChange 버전이에요.onInput: 이벤트 핸들러 함수예요. 사용자가 값을 변경하면 즉시 실행돼요. 역사적인 이유로, React에서는 비슷하게 동작하는 onChange를 사용하는 것이 관용적이에요.onInputCapture: 캡처 단계에서 실행되는 onInput 버전이에요.onInvalid: 이벤트 핸들러 함수예요. 폼 제출 시 input이 유효성 검사에 실패하면 실행돼요. 내장 invalid 이벤트와 달리, React onInvalid 이벤트는 버블링돼요.onInvalidCapture: 캡처 단계에서 실행되는 onInvalid 버전이에요.required: boolean이에요. true면, 폼을 제출하려면 값이 제공되어야 해요.size: 숫자예요. multiple={true} select의 경우, 처음에 보이는 항목의 선호 개수를 지정해요.<option>에 selected 속성을 전달하는 것은 지원되지 않아요. 대신, 비제어 select 박스는 <select defaultValue>를, 제어 select 박스는 <select value>를 사용하세요.value prop을 받으면, 제어되는 것으로 취급될 거예요.onChange 이벤트 핸들러가 필요해요.select 박스를 표시하려면 <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 { margin: 5px; }
일반적으로 모든 <select>를 <label> 태그 안에 배치할 거예요. 이렇게 하면 브라우저에게 이 라벨이 해당 select 박스와 연결되어 있다고 알려줘요. 사용자가 라벨을 클릭하면, 브라우저가 자동으로 select 박스에 포커스할 거예요. 접근성에도 필수적이에요: 스크린 리더가 사용자가 select 박스에 포커스할 때 라벨 캡션을 알려줄 거예요.
<select>를 <label> 안에 중첩할 수 없다면, <select id>와 <label htmlFor>에 같은 ID를 전달해서 연결하세요. 한 컴포넌트의 여러 인스턴스 간 충돌을 피하려면, 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>
</>
);
}
select { margin: 5px; }
기본적으로 브라우저는 목록의 첫 번째 <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 { margin: 5px; }
⚠️ 주의
HTML과 달리, 개별
<option>에selected속성을 전달하는 것은 지원되지 않아요.
사용자가 여러 옵션을 선택할 수 있게 하려면 <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>
);
}
select { display: block; margin-top: 10px; width: 200px; }
select 박스 주위에 <form>을 추가하고 내부에 <button type="submit">을 넣으세요. <form onSubmit> 이벤트 핸들러를 호출할 거예요. 기본적으로 브라우저는 폼 데이터를 현재 URL로 전송하고 페이지를 새로고침해요. e.preventDefault()를 호출해서 그 동작을 재정의할 수 있어요. new FormData(e.target)로 폼 데이터를 읽으세요.
export default function EditPost() {
function handleSubmit(e) {
// 브라우저가 페이지를 새로고침하는 것을 막아요
e.preventDefault();
// 폼 데이터를 읽어요
const form = e.target;
const formData = new FormData(form);
// formData를 fetch body로 직접 전달할 수 있어요:
fetch('/some-api', { method: form.method, body: formData });
// 브라우저가 기본적으로 하는 것처럼 URL을 생성할 수 있어요:
console.log(new URLSearchParams(formData).toString());
// 일반 객체로 작업할 수 있어요.
const formJson = Object.fromEntries(formData.entries());
console.log(formJson); // (!) 다중 select 값은 포함하지 않아요
// 또는 name-value 쌍의 배열을 얻을 수 있어요.
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>
);
}
label, select { display: block; }
label { margin-bottom: 20px; }
참고
<select>에name을 지정하세요. 예를 들어<select name="selectedFruit" />. 지정한name은 폼 데이터에서 키로 사용될 거예요. 예를 들어{ selectedFruit: "orange" }.
<select multiple={true}>를 사용하면, 폼에서 읽는FormData는 선택된 각 값을 별도의 name-value 쌍으로 포함할 거예요. 위 예시의 콘솔 로그를 자세히 살펴보세요.
⚠️ 주의
기본적으로,
<form>내부의 모든<button>은 폼을 제출할 거예요. 이건 놀랄 수 있어요! 자체 커스텀ButtonReact 컴포넌트가 있다면,<button>대신<button type="button">을 반환하는 것을 고려하세요. 그런 다음, 명시적으로 하기 위해, 폼을 제출해야 하는 버튼에는<button type="submit">을 사용하세요.
<select /> 같은 select 박스는 비제어예요. 초기 선택된 값을 전달하더라도 <select defaultValue="orange" />처럼, JSX는 초기 값만 지정하고 지금 값은 지정하지 않아요.
제어 select 박스를 렌더링하려면, value prop을 전달하세요. React는 select 박스가 항상 전달한 value를 갖도록 강제할 거예요. 일반적으로 state 변수를 선언해서 select 박스를 제어해요:
function FruitPicker() {
const [selectedFruit, setSelectedFruit] = useState('orange'); // state 변수를 선언해요...
// ...
return (
<select
value={selectedFruit} // ...select의 값이 state 변수와 일치하도록 강제해요...
onChange={e => setSelectedFruit(e.target.value)} // ... 그리고 모든 변경마다 state 변수를 업데이트해요!
>
<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>
</>
);
}
select { margin-bottom: 10px; display: block; }
⚠️ 주의
onChange없이value를 전달하면, 옵션을 선택하는 것이 불가능할 거예요.value를 전달해서 select 박스를 제어하면, 전달한 값을 항상 갖도록 강제해요. 그래서 state 변수를value로 전달하지만onChange이벤트 핸들러 동안 그 state 변수를 동기적으로 업데이트하는 것을 잊으면, React는 모든 키 입력 후 select 박스를 지정한value로 되돌릴 거예요.HTML과 달리, 개별
<option>에selected속성을 전달하는 것은 지원되지 않아요.