Select
옵션 목록에서 선택하는 드롭다운 컴포넌트
개요
Select 컴포넌트는 Radix UI의 Select Primitive를 기반으로 구축된 드롭다운 선택 컴포넌트입니다. 키보드 네비게이션과 완벽한 접근성을 제공합니다.
주요 특징
- ✅ Radix UI 기반: 검증된 headless 컴포넌트
- ✅ 키보드 네비게이션: 완벽한 키보드 지원
- ✅ 접근성 우선: WCAG 2.1 AA 준수
- ✅ 검색 가능: 타이핑으로 옵션 검색
- ✅ TypeScript: 완벽한 타입 지원
설치
npx @vortex/cli add select기본 사용법
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from "@vortex/ui-foundation";
export default function App() {
return (
<Select>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="옵션 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">옵션 1</SelectItem>
<SelectItem value="option2">옵션 2</SelectItem>
<SelectItem value="option3">옵션 3</SelectItem>
</SelectContent>
</Select>
);
}컴포넌트 구조
Select는 여러 하위 컴포넌트로 구성됩니다.
<Select>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem />
</SelectContent>
</Select>언제 사용하는가
✅ 권장 사용 사례
- 단일 선택: 여러 옵션 중 하나 선택
- 카테고리 선택: 제품 카테고리, 태그 등
- 설정 변경: 언어, 테마, 정렬 기준 등
- 필터링: 목록 필터링 옵션
- 폼 입력: 국가, 직업, 연령대 등
실전 예제
폼에서 사용
<form className="space-y-4">
<div>
<label htmlFor="country" className="block text-sm font-medium mb-2">
국가
</label>
<Select>
<SelectTrigger id="country">
<SelectValue placeholder="국가 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="kr">대한민국</SelectItem>
<SelectItem value="us">미국</SelectItem>
<SelectItem value="jp">일본</SelectItem>
</SelectContent>
</Select>
</div>
</form>언제 사용하지 말아야 하는가
| 상황 | 대신 사용할 컴포넌트 |
|---|---|
| 2-3개 옵션 | <RadioGroup> |
| 다중 선택 | <Checkbox> |
| On/Off 토글 | <Switch> |
| 텍스트 입력 | <Input> |
| 날짜 선택 | <DatePicker> |
Advanced Usage
Controlled 컴포넌트
import { useState } from "react";
function ControlledSelect() {
const [value, setValue] = useState("");
return (
<Select value={value} onValueChange={setValue}>
<SelectTrigger>
<SelectValue placeholder="선택하세요" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">옵션 1</SelectItem>
<SelectItem value="option2">옵션 2</SelectItem>
</SelectContent>
</Select>
);
}Disabled 옵션
<Select>
<SelectTrigger>
<SelectValue placeholder="선택하세요" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">옵션 1</SelectItem>
<SelectItem value="option2" disabled>
옵션 2 (비활성)
</SelectItem>
<SelectItem value="option3">옵션 3</SelectItem>
</SelectContent>
</Select>그룹화
import { SelectGroup, SelectLabel } from "@vortex/ui-foundation";
<Select>
<SelectTrigger>
<SelectValue placeholder="과일 선택" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>과일</SelectLabel>
<SelectItem value="apple">사과</SelectItem>
<SelectItem value="banana">바나나</SelectItem>
</SelectGroup>
<SelectGroup>
<SelectLabel>채소</SelectLabel>
<SelectItem value="carrot">당근</SelectItem>
<SelectItem value="tomato">토마토</SelectItem>
</SelectGroup>
</SelectContent>
</Select>;접근성 (Accessibility)
Select 컴포넌트는 WCAG 2.1 AA 기준을 준수합니다.
ARIA Attributes
자동으로 제공:
role="combobox": Radix UI가 자동 설정aria-expanded: 드롭다운 상태 자동 설정aria-controls: 콘텐츠와 자동 연결
키보드 네비게이션
- Space/Enter: 드롭다운 열기/닫기
- Arrow Up/Down: 옵션 탐색
- Home/End: 처음/마지막 옵션으로 이동
- Esc: 드롭다운 닫기
- 타이핑: 옵션 검색
Best Practices
1. 명확한 레이블
// ✅ Good
<label htmlFor="language">언어</label>
<Select>
<SelectTrigger id="language">
<SelectValue placeholder="언어 선택" />
</SelectTrigger>
</Select>
// ❌ Bad: 레이블 없음
<Select>...</Select>2. 적절한 Placeholder
// ✅ Good: 선택 안내
<SelectValue placeholder="국가를 선택하세요" />
// ❌ Bad: 모호한 문구
<SelectValue placeholder="선택" />3. 옵션 개수 고려
// ✅ Good: 4개 이상일 때 Select 사용
<Select>
<SelectContent>
{countries.map((country) => (
<SelectItem key={country.code} value={country.code}>
{country.name}
</SelectItem>
))}
</SelectContent>
</Select>
// ❌ Bad: 2-3개는 RadioGroup 사용TypeScript
import { Select, SelectProps } from "@vortex/ui-foundation";
interface CustomSelectProps {
label: string;
options: Array<{ value: string; label: string }>;
value?: string;
onValueChange?: (value: string) => void;
}
function CustomSelect({
label,
options,
value,
onValueChange,
}: CustomSelectProps) {
return (
<div>
<label className="block text-sm font-medium mb-2">{label}</label>
<Select value={value} onValueChange={onValueChange}>
<SelectTrigger>
<SelectValue placeholder="선택하세요" />
</SelectTrigger>
<SelectContent>
{options.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
);
}성능 최적화
많은 옵션 처리
import { useMemo } from "react";
function LargeSelect({ items }: { items: string[] }) {
const memoizedItems = useMemo(
() =>
items.map((item) => (
<SelectItem key={item} value={item}>
{item}
</SelectItem>
)),
[items]
);
return (
<Select>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>{memoizedItems}</SelectContent>
</Select>
);
}관련 컴포넌트
- RadioGroup: 2-3개 옵션 선택
- Checkbox: 다중 선택
- Combobox: 검색 가능한 선택
- Input: 텍스트 입력
참고 자료
지원 및 피드백
문제가 발생하거나 개선 제안이 있으신가요?
- GitLab Issues: vortex/platform/issues
- Slack: #vortex-design-system
Last updated on