선택 목록
정해진 목록에서 하나를 고르는 파인 칸입니다. 트리거는 입력칸과 같은 면이고, 열린 목록은 드롭다운 층(60)에 뜨는 판으로 모서리를 꺾지 않습니다.
- import
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger } from "@uyoolabs/ui/form";- 쓰는 경우
- 7개 이상이거나 자리가 좁을 때 씁니다. 옵션에 아이콘 · 아바타 · 설명 · 비활성 이유 · 그룹 머리가 필요할 때도 Select 입니다. 2~6개는 RadioGroup · SegmentedControl 로 펼칩니다.
- 쓰지 않는 경우
- 두세 개를 Select 에 숨기지 않습니다. placeholder 를 라벨 대신 쓰지 않습니다(고른 뒤 무엇을 고른 칸인지 사라집니다). 목록에서 슬그머니 빼지 말고 비활성 + 설명 줄로 이유를 적습니다. 고르는 순간 페이지를 옮기거나 다른 칸을 없애지 않습니다(WCAG 3.2.2). 검색 · 여러 개 · 새 값이 필요하면 Combobox(W2)입니다.
- 읽기 전용
- 고를 수 없는 값은 Select 를 쓰지 않고 값만 읽기 전용 면(Input readOnly)으로 보입니다.
네이티브 select 와 Select
| NativeSelect (./ui) | Select (./form · radix) | |
|---|---|---|
| 쓰는 곳 | 서버 폼 · radix 없는 소비자 · 모바일 비중이 큰 화면 · 글자만 있는 옵션 | 옵션에 아이콘 · 설명 · 비활성 이유 · 그룹 머리가 필요한 앱 화면 |
| 열린 목록 | OS 가 그립니다(재질 · 다크 · 서체가 OS 를 따릅니다) | 카톤 뜸 판(z 60) · 다크 · Noto |
| 빈 값 | <option value=""> | 빈 문자열 값을 둘 수 없습니다. “지정 안 함” 항목을 만듭니다 |
한 폼 안에서 둘을 섞지 않습니다. 둘 다 name 을 주면 FormData 에 값이 들어갑니다.
기본
라벨 · 설명 줄 · 비활성 항목(이유) · 오류
역할을 고르지 않았습니다. 초대할 역할을 선택합니다.
결제 수단이 있으면 통화를 바꿀 수 없습니다.
그룹 · 구분선 · 언어 이름
그룹 머리는 그룹의 이름이 됩니다. 8줄을 넘으면 위 · 아래 스크롤 단추가 나옵니다.
불러오는 중 · 빈 목록 · 거르기 바
키보드
APG Select-Only Combobox 입니다. 한 · 일 IME 가 조합 중인 키는 radix 에 넘기지 않습니다(isComposing 가드).
| 자리 | 키 | 동작 |
|---|---|---|
| 트리거 | Enter · Space · ↓ · ↑ | 열고 고른 항목(없으면 첫 항목)에 포커스를 둡니다 |
| 트리거 | 글자 | 닫힌 채 타입어헤드로 고릅니다(라틴 글자) |
| 목록 | ↑ · ↓ | 옮깁니다. 비활성 항목은 건너뜁니다 |
| 목록 | Home · End | 처음 · 끝 항목으로 갑니다 |
| 목록 | 글자 | 타입어헤드. 한 · 일 조합 중에는 움직이지 않습니다 |
| 목록 | Enter · Space | 고르고 닫습니다. 포커스는 트리거로 돌아갑니다 |
| 목록 | Esc | 값을 바꾸지 않고 닫습니다. 포커스는 트리거로 |
| 목록 | Tab | 열린 동안 막힙니다(radix 동작, APG 의 ‘Tab 으로 고르고 나감’과 다릅니다) |
내장 문구
lang(ko · en · ja)으로 고르고 labels 로 일부를 바꿉니다(ADR 0011).
| 키 | ko | en | ja |
|---|---|---|---|
| placeholder | 선택 | Select | 選択 |
| empty | 고를 항목이 없습니다. | No options. | 選べる項目がありません。 |
| loading | 불러오는 중 | Loading… | 読み込み中… |
props
소스의 타입과 JSDoc 에서 생성한 표입니다. 컴포넌트를 고치면 pnpm gen 으로 다시 만듭니다.
Select
| prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| loading | boolean | false | 옵션을 불러오는 중. 트리거 꺾쇠 자리에 스피너 + aria-busy, 목록에 labels.loading |
| lang | "ko" | "en" | "ja" | — | 내장 문구의 언어 |
| labels | Partial<SelectLabels> | — | 내장 문구 중 바꿀 것만 |
이 밖에 Radix Select.Root props를 그대로 받습니다. 기본값을 바꾼 것은 defaultOpen=false 입니다.
SelectTrigger
| prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| size | "sm" | "md" | "md" | sm 28(거르기 바 · 표 안, 폭은 값에 맞춤) · md 36(기본, 폭 100%) |
| invalid | boolean | — | 오류 경계. aria-invalid 를 단다. 오류 문장은 Field 가 맡는다 |
| placeholder | ReactNode | — | 무엇을 고르는지(“역할 선택”). 없으면 labels.placeholder |
| prefix | ReactNode | — | 값 앞에 흐리게 두는 거르기 이름(sm 거르기 바의 “담당”). 접근성 이름은 aria-label 로 따로 준다 |
이 밖에 Radix Select.Trigger props(asChild · prefix 제외)를 그대로 받습니다.
SelectContent
| prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| empty | boolean | — | 고를 항목이 없다. labels.empty 를 보인다 |
이 밖에 Radix Select.Content props(position 제외)를 그대로 받습니다. 기본값을 바꾼 것은 sideOffset=4 · collisionPadding=8 입니다.
SelectItem
| prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| description | ReactNode | — | 둘째 줄 12px muted. 비활성 이유도 여기에 쓴다(읽히는 색을 지킨다). 항목의 접근성 이름에 이어 붙는다 |
| icon | ReactNode | — | 이름 앞 16(아바타 20 도 된다). 고르면 트리거에도 함께 보인다 |
이 밖에 Radix Select.Item props(asChild 제외)를 그대로 받습니다.