커스텀 셀렉트 및 콤보박스 시스템
목적
커스텀 셀렉트 및 콤보박스 시스템은 드롭다운 옵션, 자동 완성 검색 선택기(콤보박스), 다중 선택 토큰 입력 필드를 설계하고 구조화하기 위한 체계적인 방법론을 제공합니다.
표준 HTML <select> 요소는 브라우저 간 일관된 스타일링이 notoriously 어렵고, 개별 선택 항목 내에 설명, 아이콘, 배지, 서브 그리드와 같은 풍부한 레이아웃 구성을 지원할 수 없습니다. 그러나 커스텀 드롭다운은 치명적인 접근성 오류, 키보드 트랩, 사용성 버그의 빈번한 원인이 됩니다. 이 스킬은 커스텀 셀렉트 컴포넌트가 시각적으로 일관되고, 반응성이 뛰어나며, 완전히 접근 가능하도록(WCAG 2.2 AA 준수) 설계, 공간 및 상호작용 표준을 수립합니다.
사용 사례
다음과 같은 경우 이 시스템을 적용하세요:
- 풍부한 콘텐츠 드롭다운: 시각적 표시기, 부제목, 보조 메타데이터 또는 상태 배지가 필요한 선택 항목(예: 국가 선택기(국기 아이콘 포함), 워크스페이스 전환기, 계정 프로필).
- 검색 가능한 선택기(콤보박스): 10개 이상의 옵션이 있고 사용자가 인라인 검색 입력을 통해 선택 항목을 필터링할 수 있어야 하는 드롭다운(예: 긴 주/도 목록, 태그 선택).
- 다중 선택 토큰 필드: 여러 선택이 허용되며 트리거 컨테이너 내부 또는 인접에 해제 가능한 배지/칩으로 렌더링되어야 하는 필드.
- 동적 구성 필터: 풍부한 레이아웃 정렬과 즉각적인 컨텍스트 피드백이 필요한 고밀도 필터 컨트롤(예: 전자상거래 또는 데이터 대시보드 사이드바).
사용하지 말아야 할 경우
다음과 같은 경우 이 시스템을 적용하지 마세요:
- 낮은 옵션 볼륨(2~5개 옵션):
segmented-control-system또는 표준 그룹화된 라디오 버튼을 사용하세요. 이렇게 하면 추가 클릭 뒤에 옵션을 숨기지 않아 인지 부하를 줄일 수 있습니다. - 글로벌 페이지 탐색: 드롭다운 항목을 클릭하면 사용자가 다른 페이지나 사이트맵 노드로 즉시 리디렉션되는 경우
site-navigation-system또는 중첩 드롭다운 메뉴를 사용하세요. 선택 입력은 사이트맵을 탐색하기 위한 것이 아니라 속성을 편집하기 위한 의미론적 양식 필드입니다. - 표준 스타일링되지 않은 양식: 일반적이거나 우선순위가 낮은 유틸리티 양식(예: 기본 연락처 필드)의 경우 기본 브라우저
<select>입력을 사용하세요. 네이티브 드롭다운은 완벽하고 무료인 모바일 반응성과 네이티브 스크린 리더 지원을 제공합니다. - 전체 화면 명령 팔레트: 단일 양식 값을 선택하는 대신 전체 앱의 페이지와 작업을 검색하는 것이 목표인 경우
command-palette-system을 사용하세요.
입력
커스텀 셀렉트 또는 콤보박스를 설계하기 전에 다음 요구 사항을 수집하세요:
- 옵션 개수 및 밀도: 몇 개의 옵션이 존재합니까(예: 5, 50, 500개 이상)? 최대 문자 길이는 얼마입니까?
- 선택 유형: 단일 선택 vs. 다중 선택? 정적 목록 vs. 비동기적으로 필터링된 쿼리 목록(콤보박스)?
- 데이터 풍부함: 옵션에 보조 시각 자료(아이콘, 아바타, 플래그, 컬러 칩) 또는 지원 텍스트(서브 레이블, 가격 수정자, 활성 사용자 수)가 필요합니까?
- 레이아웃 컨텍스트: 고밀도 사이드바, 넓은 랜딩 페이지, 오버레이 모달 또는 영구 설정 대시보드 중 어디에 위치합니까?
- 브랜드 토큰: 간격 척도(
fluid-spacing-system), 타이포그래피 척도(fluid-typography-system), 포커스 링(focus-indicator-design-system), 그림자 척도(elevation-and-depth-system).
출력
이 시스템은 다음과 같은 디자인 결과물을 생성합니다:
- 해부도 명세: 트리거와 드롭다운 패널 모두에 대한 간격, 정렬, 아이콘, 텍스트 잘림 규칙, 테두리/배경 레이어를 보여주는 상세 청사진.
- 상태 및 상호작용 매트릭스: 호버, 활성/열림, 선택됨, 포커스됨, 비활성화됨, 유효성 검사 오류 상태에 대한 정의된 시각적 스타일.
- 반응형 적응 모델: 데스크톱 드롭다운이 모바일 뷰포트로 변환되는 방법(예: 하단 서랍/시트 또는 네이티브 폴백 오버레이로 변환)을 설명하는 구조적 사양.
- 접근성 맵(WAI-ARIA 및 키보드): 개발자에게 전달할 정확한 역할, 라이브 리전 선언, 포커스 추적 상태 및 키 매핑 동작.
워크플로우
1. 컴포넌트 해부도 구조화
완전한 커스텀 셀렉트 시스템은 두 가지 기본적인 공간 레이어로 구성됩니다:
A. 트리거(필드)
- 컨테이너: 인접한 양식 입력과 높이 일치(일반적으로 터치 대상 허용을 위해 40px~48px). 중립적 외곽선(페이지 배경 대비 3:1)과 정의된 패딩(보통
12px 16px)을 사용합니다. - 값/플레이스홀더 슬롯: 왼쪽에 위치. 비활성 텍스트는 플레이스홀더를 나타냅니다(필드 배경 대비 >= 4.5:1). 선택된 텍스트는 기본 중립 두께로 스타일링됩니다.
- 시각적 표시(화살표 셰브론): 맨 오른쪽에 위치. 접을 수 있는 콘텐츠를 나타내기 위해 아래쪽을 가리키는 뚜렷한 셰브론을 사용합니다. 메뉴가 활성화되면 셰브론을 180도 회전시킵니다.
- 선택된 배지(다중 선택 전용): 개별 닫기(x) 컨트롤이 있는 컴팩트한 인라인 칩으로, 우아하게 줄 바꿈되거나 개수 수정자(예: "+3 more")로 잘립니다.
B. 드롭다운 패널(메뉴)
- 오버레이 컨테이너: 더 높은 Z축 레벨(
elevation-and-depth-system레벨 3/4)에 위치. 기본적으로 트리거 아래에 렌더링되거나, 뷰포트 가장자리가 아래 공간을 제한하는 경우 위에 렌더링됩니다. 배경 페이지에서 분리하기 위해 뚜렷한 그림자(예: 부드러운 블러가 있는box-shadow)를 사용합니다. - 스크롤 컨테이너: 패널이 페이지에서 벗어나는 것을 방지하기 위해 최대 높이 제약 조건(일반적으로
240px~320px/ 5~8개 항목)을 설정합니다. 더 긴 목록의 경우 스크롤바 이동을 방지하는 가시적인 스크롤 트랙을 사용합니다. - 검색 입력(콤보박스 전용): 메뉴 활성화 시 지속적인 포커스를 유지하며 드롭다운 패널 상단에 고정된 스티키 검색 입력.
C. 옵션 항목(선택 항목)
- 레이아웃: 왼쪽에 시각적 자산, 중앙에 기본 텍스트(및 리치 옵션의 경우 부제목), 오른쪽에 선택 상태 표시기(예: 체크마크)로 구성된 수평 플렉스 레이아웃.
- 안전 패딩: 최소 수직 패딩
8px, 수평은 트리거의 수평 패딩과 일치(12px~16px).
+------------------------------------------+
| 국가 선택 [v] | <-- 트리거(닫힘)
+------------------------------------------+
+------------------------------------------+
| [Q] 국가 검색... | <-- 스티키 검색 입력
+------------------------------------------+
| [x] 캐나다 | <-- 옵션(선택됨 및 포커스됨)
| ISO: CA | +1 국가 코드 |
|------------------------------------------|
| [ ] 독일 | <-- 옵션(기본)
| ISO: DE | +49 국가 코드 |
+------------------------------------------+
2. 상태 및 피드백 매트릭스 공식화
컴포넌트의 모든 수명 주기 상태에 대해 명확하고 모호하지 않은 스타일을 설계하세요:
- 기본 상태: 트리거는 명확한 텍스트 레이블(최소 4.5:1 대비)과 함께 명확한 외곽선(페이지 배경 대비 최소 3:1)을 사용합니다.
- 호버 상태: 상호작용 가능성을 신호하기 위해 트리거(예: 낮은 대비 회색)와 옵션 행에 미묘한 배경 색조 변화. 커서는
pointer로 설정됩니다. - 포커스 상태: 활성 요소를 둘러싸는 매우 가시적인 포커스 링. 콤보박스의 경우 목록이 열려 있는 동안 포커스는 검색 입력에 있어야 하지만, 강조 표시된 목록 옵션에는 시각적 포커스 처리(예: 배경 색조 또는 활성 외곽선)를 사용합니다.
- 활성/확장 상태: 셰브론이 회전하고, 트리거 외곽선 색상이 변경되며(예: 기본 브랜드 색상), 드롭다운 패널이 부드러운 높이 및 불투명도 전환(150ms~250ms)과 함께 나타납니다.
- 선택 상태: 선택 시 옵션 행이 시각적으로 변경됩니다. 맨 오른쪽에 고대비 체크마크 아이콘과 미묘한 배경 채움을 사용합니다. 선택을 나타내기 위해 색상에만 의존하지 마십시오.
- 비활성화 상태: 시각적 불투명도가 40%~50%로 감소. 커서는
not-allowed표시기가 되며, 요소는 탭 인덱스에서 건너뜁니다. - 오류/무효 상태: 트리거 외곽선이 유효성 검사 오류 색상(일반적으로 고대비 빨간색, >= 3.1 대비)으로 바뀌고, 입력 아래에 오류 메시지와 오류 아이콘이 표시됩니다.
3. 공간 및 배치 규칙 수립
레이아웃 충돌 및 누적 레이아웃 이동(CLS)을 방지하려면:
- 동적 위치 지정(플립 동작): 뷰포트 경계를 계산합니다. 드롭다운 컨테이너가 하단 뷰포트 접힘 부분에 가까우면 정렬을 반전시켜 트리거 위쪽으로 슬라이드 업합니다.
- 너비 정렬: 드롭다운 패널은 트리거의 왼쪽 및 오른쪽 가장자리와 정확히 정렬되거나, 트리거와 일치하는 정의된 최소 너비를 가져 시각적 불안정을 방지해야 합니다.
- 오버레이 격리: 레벨 3(고정/플로팅 UI) 또는 레벨 4(오버레이 및 대화 상자)와 일치하는 CSS
z-index스택을 사용합니다. 패널이 항상 인접한 양식 요소, 배경 및 레이아웃 카드 위에 렌더링되도록 하십시오.
4. 반응형 및 모바일 적응 설계
다중 열 또는 넓은 데스크톱 드롭다운 메뉴를 작은 모바일 뷰포트에 절대 강제로 적용하지 마십시오. 다음 적응형 레이아웃 규칙을 적용하세요:
패턴 A: 모바일 하단 시트(리치 옵션에 권장)
640px 미만의 화면 크기(또는 표준 태블릿 중단점)에서 커스텀 드롭다운 패널을 슬라이딩 하단 시트로 변환합니다:
- 트리거: 트리거를 탭하면 전체 너비 하단 시트 오버레이가 열립니다.
- 스크림: 반투명 어두운 배경(40%~60% 불투명도)이 기본 콘텐츠를 덮어 배경 요소를 상호작용 불가능하게 만듭니다.
- 헤더: 시트에는 명확한 제목과 오른쪽 상단 모서리에 있는 큰 터치 접근 가능 "닫기"(x) 버튼이 있는 스티키 헤더가 포함됩니다.
- 엄지 도달성: 옵션 행은 전체 화면 너비를 차지하고 터치 대상 높이가 증가(최소 48px, 권장 56px)하여 손가락 탭 선택이 용이합니다.
패턴 B: 네이티브 폴백(단순 목록에 권장)
모바일 뷰포트에서 화면 판독기 및 시각적 DOM에서 커스텀 마크업을 완전히 숨기고, 시각적으로 숨겨지고 레이어 스택된 네이티브 <select> 요소로 대체합니다:
- 작동 방식: 표준
<select>를 커스텀 트리거 바로 위에 배치하고opacity: 0으로 스타일링합니다. - 결과: 사용자는 브랜드화된 트리거를 보지만, 탭하면 네이티브 OS 선택 휠(iOS Picker 또는 Android Dialog)이 활성화되어 타의 추종을 불허하는 네이티브 성능과 로컬 접근성을 제공합니다.
5. 스크린 리더 및 키보드 아키텍처 정의
커스텀 셀렉트 요소는 완전한 보조 기술을 지원해야 합니다. 전달을 위해 이 정확한 동작을 지정하세요:
ARIA 매핑 및 시맨틱
- 트리거 버튼:
role="combobox",aria-haspopup="listbox",aria-expanded="true/false",aria-controls="listbox-id"가 있어야 합니다. - 드롭다운 패널:
role="listbox", 트리거의 ID로 레이블 지정(`aria-labelledby="trigger-id"")되어야 합니다. - 옵션 항목:
role="option"이 있어야 합니다. 현재 선택된 항목은aria-selected="true"를, 다른 항목은aria-selected="false"를 가져야 합니다. - 포커스 관리: 자동 완성 콤보박스의 경우 검색 입력에
aria-autocomplete="list"가 있어야 합니다. 사용자가 위/아래 화살표 키를 움직일 때 시각적으로 강조 표시된 옵션을 추적하기 위해 입력에aria-activedescendant="option-id"를 사용하세요. - 라이브 알림:
aria-live="polite"또는 지정된 스크린 리더 알림 요소를 사용하여 선택 상태 변경 또는 개수 업데이트(예: "5개 옵션을 찾았습니다. 화살표 키를 사용하여 탐색하세요.")를 알립니다.
키보드 상호작용 표
명세서에는 이러한 정확한 단축키 매핑이 필수로 포함되어야 합니다:
| 동작 | 키 입력 | 예상 동작 |
|---|---|---|
| 메뉴 열기 | Space 또는 Enter 또는 ArrowDown | 드롭다운 패널을 열고 첫 번째 옵션(또는 검색)에 포커스를 둡니다. |
| 메뉴 닫기 | Escape 또는 Tab | 패널을 닫고 키보드 포커스를 트리거로 되돌립니다. |
| 옵션 탐색 | ArrowDown / ArrowUp | 활성 강조 표시를 다음 또는 이전 옵션 행으로 이동합니다. |
| 옵션 선택 | Space 또는 Enter | 강조 표시된 옵션을 선택하고, 값을 업데이트하고, 패널을 닫습니다. |
| 첫 번째/마지막 항목 | Home / End | 활성 강조 표시를 옵션 목록의 절대 시작 또는 끝으로 이동합니다. |
| 점프 검색 | 모든 영숫자 키 | 정적인 경우 포커스가 해당 문자로 시작하는 첫 번째 옵션으로 즉시 이동합니다. |
결정 규칙
커스텀 셀렉트 옵션 결정 트리
총 옵션 개수는 얼마입니까?
├── 2~5개 옵션 ─────────> 세그먼트 컨트롤 또는 그룹화된 라디오 버튼 사용
├── 6~10개 옵션 ────────> 커스텀 셀렉트 사용(단일 열, 검색 입력 없음)
└── 10개 초과 옵션 ────> 콤보박스 사용(검색 입력이 통합된 커스텀 셀렉트)
올바른 선택 패턴 선택
| 요구 사항 | 표준 셀렉트 사용 | 검색 가능한 콤보박스 사용 | 다중 선택 토큰 사용 |
|---|---|---|---|
| 선택 제한 | 단일 값만 | 단일 값만 | 여러 값 동시에 |
| 옵션 규모 | 6~15개 항목 | 15~100+개 항목 | 5~50개 항목 |
| 마찰 유형 | 낮은 탐색 | 빠른 대상 검색 필요 | 누적 조립 |
| 옵션 레이아웃 | 단순 텍스트 행 | 단순 또는 리치 목록 행 | 칩/토큰 줄 바꿈 레이아웃 |
제약 조건
- 포커스 보존:
Escape를 누르거나 외부를 클릭하여 드롭다운을 닫을 때 포커스가 절대 손실되거나 최상위 사이트맵 레벨로 재설정되어서는 안 됩니다. 트리거 요소로 프로그래밍 방식으로 반환되어야 합니다. - 포커스 가시성(WCAG 2.2 SC 2.4.11): 트리거 또는 활성 옵션의 포커스 표시기가 고정 페이지 헤더, 플로팅 하단 바 또는 겹치는 오버레이에 의해 숨겨지거나 가려져서는 안 됩니다.
- 터치 대상(WCAG 2.2 SC 2.5.8): 모든 옵션 행과 트리거 요소는 최소 클릭 가능 크기가
24x24px여야 하며,40px~48px높이가 기본 레이아웃 요구 사항이어야 모바일 장치에서 터치 중복을 방지할 수 있습니다. - 색상 대비(WCAG 2.1 SC 1.4.11): 선택되지 않은 옵션 텍스트는 배경에 대해 최소 4.5:1의 대비율을 유지해야 합니다. 선택 표시기(체크마크 등)는 대비 3:1을 유지해야 합니다.
- 스크롤바 일관성: 드롭다운 패널이 긴 목록을 스크롤할 때 콘텐츠가 CSS
scrollbar-gutter: stable을 통해 스크롤바 아래에서 이동하거나 잘리지 않도록 하십시오.
고려 사항
- 성능: 500개 이상의 옵션이 있는 콤보박스의 경우 가상화(윈도우)를 구현하여 뷰포트에 표시되는 항목만 렌더링하고 DOM 노드 수를 낮게 유지합니다.
- 지연 로딩: 옵션 데이터가 서버에서 오는 경우 트리거가 포커스를 받거나 활성화될 때까지 페치를 지연시킵니다. 페치 중에는 로딩 스피너(또는 스켈레톤 행)와
aria-busy="true"를 표시합니다. - 오류 복구: 네트워크 시간 초과 또는 페치 실패의 경우 결과 없음 화면을 표시하는 대신 동일한 드롭다운 패널 내에 재시도 버튼이 있는 인라인 오류 메시지를 표시합니다.
- 현지화: 정렬 문자, 날짜 형식, 통화 기호가 올바른 로케일을 따르는지 확인하세요. 아랍어 또는 히브리어와 같은 RTL(오른쪽에서 왼쪽) 언어의 경우
dir="rtl"속성을 사용하여 전체 위젯 방향을 자동으로 미러링하도록 지정하세요.
관련 스킬
fluid-spacing-system— 일관된 양식 레이아웃을 위한 간격 토큰.fluid-typography-system— 옵션 레이블 내에서 처리 가능한 텍스트 크기 및 행간.focus-indicator-design-system— 커스텀 셀렉트 트리거에 대한 접근 가능한 포커스 링.elevation-and-depth-system— 드롭다운 패널을 페이지에서 분리하는 그림자 레벨.site-navigation-system— 전체 페이지 전환을 위해 이 패턴을 사용하지 말아야 할 때.segmented-control-system— 2~5개 옵션을 위한 경량 대안.command-palette-system— 앱 전체 명령 검색을 위한 대안 디자인.iconography-system— 선택 입력 내에서 일관된 아이콘 스타일을 유지합니다.