OptionList
aria-activedescendant를 쓰는 role="listbox"입니다. 옵션은 문자열입니다. 키보드는 Arrow, Home, End, Enter, Space입니다. Escape는 부모 Popover를 닫을 수 있도록 처리하지 않습니다.
단일 선택의 value는 string | null입니다. 다중 선택의 value는 string[]입니다. 선택된 옵션은 font-weight: 400을 유지하고 액센트를 옅게 깐 행 배경(color.bg.selected, 액센트 12%)을 씁니다. 하이라이트된 선택 옵션은 20%(color.accent.soft-strong)입니다. 행 사이 간격은 2px입니다. 호버는 @media (hover: hover)로 제한합니다.
다중 선택은 모든 행에 체크 영역을 둡니다. 선택되면 상자를 채우고 CSS로 체크를 그립니다.
옵션은 OptionList.Root 안의 OptionList.Option 파트입니다.
Combobox는 id, activeValue, onActiveValueChange, tabIndex={-1}를 넘겨 입력이 포커스와 aria-activedescendant를 갖게 할 수 있습니다. 비제어 목록은 tabIndex={0}을 유지합니다.
언제 쓰나요
언제: Popover나 BottomSheet 안의 오버레이 listbox. 단일 또는 다중 문자열 옵션. 키보드 listbox 패턴.
쓰지 않을 때: 페이지에 계속 남는 선택지 → Radio나 Checkbox. 같은 값을 Radio/Checkbox에 이중으로 연결하지 마세요.
Props
| 이름 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
| selectionMode | "single" | "multiple" | 아니요 | "single" | single은 onValueChange(string)을, multiple은 onValueChange(string[])을 호출합니다. |
| value | string | null | readonly string[] | 예 | — | 선택된 값. selectionMode가 multiple이면 값 배열. |
| onValueChange | (value: string | string[]) => void | 예 | — | 선택 변경. single은 문자열을, multiple은 다음 배열을 전달합니다. |
| id | string | 아니요 | — | Listbox id. 생략하면 자동 생성됩니다. 옵션 id는 여기서 파생됩니다. |
| tabIndex | number | 아니요 | 0 | Listbox tabIndex. combobox 입력이 포커스를 가질 때는 -1을 전달합니다. |
| activeValue | string | null | 아니요 | — | 제어 하이라이트 값. 하이라이트를 목록 안에서 관리하려면 생략합니다. |
| onActiveValueChange | (value: string | null) => void | 아니요 | — | 키보드나 포인터가 하이라이트를 옮길 때 호출됩니다. |
| aria-label | string | 아니요 | — | 보이는 레이블이 없을 때의 이름. |
| 이름 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
| value | string | 예 | — | 선택 값. |
| children | string | 예 | — | 보이는 레이블. 텍스트만 지원합니다. |
| disabled | boolean | 아니요 | false | 포인터와 키보드 선택에서 제외합니다. |