WCAG 2.2 AA 준수 React DatePicker 제작 가이드
개발팀은 Claude가 생성한 WAI-ARIA APG의 "Date Picker Dialog" 패턴 기반 DatePicker 코드를 시작점으로 삼았습니다. 초기 프롬프트는 WCAG 2.1/2.2 AA 수준 요구사항을 명시했습니다: aria-describedby이 포함된 입력 필드, 트리거 버튼, role="dialog" 모달 대화상자, 그리드 기반 달력 테이블. 하지만 원본 버전에서 포커스, 탐색, 접근성에 치명적인 문제가 드러났습니다.
AI는 기본 키보드 탐색(화살표 키, Home/End, PageUp/Down, Enter/Space, Escape), 그리드셀 요소의 roving tabindex, 월 변경 시 aria-live="polite"를 구현했습니다. 그러나 VoiceOver와 NVDA 테스트에서 문제점이 확인됐습니다: 열 때 선택된 날짜에 포커스가 가지 않고, aria-live 발표가 대기열에 쌓이며, 반복 클릭 시 대화상자가 깜빡였습니다.
실전 접근성을 위한 APG 패턴 변형
APG 명세는 중첩 버튼 없이 <td role="gridcell">을 권장하며, 수동 onClick/onKeyDown과 tabindex에 의존합니다. 하지만 실제 테스트에서 <td> 내부 <button> 사용의 명확한 장점이 확인됐습니다:
- 추가 코드 없이 네이티브 포커스 처리와 Enter/Space 지원.
- 스크린 리더를 위한 자동 의미 전달.
- aria-disabled나 preventDefault 없이 내장된 비활성화 상태.
- 마우스나 키보드에서 안정적인 클릭 이벤트.
이는 의도된 선택입니다: APG는 가이드일 뿐, 실제 디바이스 테스트가 우선입니다. 우리는 4.5:1 이상 대비, CSS Modules, Date/Intl API 포맷팅을 사용해 React/TypeScript 외 외부 의존성을 없앴습니다.
기능 및 UX 문제 수정
원본 코드는 index.html 누락과 TypeScript 오류로 컴파일되지 않았습니다. 수정 후 추가 문제가 드러났습니다:
기능 버그:
- minDate/maxDate 범위 외 날짜가 비활성화 셀 대신 다른 달로 점프.
- 입력 필드 지우기 불가.
시각 문제:
- 셀 포커스 스타일 누락.
- td 크기 불균일.
접근성:
- 열 때 선택 날짜 포커스 없음—스크린 리더 침묵.
- 월 헤더 aria-live="polite"로 빠른 탐색 시 발표 대기.
- 트리거 블러 + 클릭 시 대화상자 깜빡임.
수정 사항:
- 열 때 값 또는 오늘에 포커스; 스크린 리더가 맥락(요일, 날짜, 월, 년) 발표.
- 즉시 월 발표를 위한 별도 숨김 영역 aria-live="assertive".
- 선택 후 포커스 트리거로 복귀, 업데이트된 aria-label.
- 비활성화 일 있더라도 값의 월 표시.
- OK/Cancel 제거: Enter 확인, Esc 닫기.
컴포넌트 구조와 키보드 탐색
Props: value (Date | null), onChange, minDate?, maxDate?, disabledDates?, locale?.
주요 ARIA:
- 입력: 형식 설명 aria-describedby, readonly.
- 트리거: 동적 aria-label ("선택됨: MM/DD/YYYY" 또는 "날짜 선택").
- 대화상자: role="dialog", aria-modal="true", 포커스 트랩.
- 그리드: table role="grid", button role="gridcell" td, 값에 aria-selected, 사용 불가 날짜에 aria-disabled.
- 월 헤더: polite 영역 aria-live="assertive".
탐색:
- 화살표 키: 인접 일.
- Home/End: 월 첫/마지막 일.
- PageUp/Down: ±1개월.
- Shift+PageUp/Down: ±1년.
- Enter/Space: 선택.
- Escape: 닫기.
주요 교훈
- AI는 뼈대(ARIA, 탐색)를 빠르게 만들지만, 스크린 리더 테스트 필수.
- <td> 내 <button>이 브라우저 + 스크린 리더에서 순수 gridcell보다 안정적.
- 월 탐색 중 대기 방지 aria-live="assertive".
- 포커스 관리: 열 때 값/오늘, 트리거 복귀.
- 최소 스택: React + TS, 라이브러리 없음.
이 컴포넌트는 단일 날짜 선택기로 프로덕션 준비 완료이며, 연도/범위 확장을 위한 오픈 코드입니다.
— Editorial Team
아직 댓글이 없습니다.