접근성
모든 피커 컴포넌트는 접근성 지원이 내장되어 제공됩니다. 키보드 탐색, ARIA 속성, 포커스 관리는 Styled, Tailwind v3/v4, Headless 등 모든 버전에서 별도 설정 없이 바로 작동합니다.
표준적인 사용에는 추가 설정이 필요하지 않습니다. 이 페이지는 포함된 기능들을 문서화하여, 사용자가 직접 만든 UI에서 패턴을 감사, 확장 또는 복제할 수 있도록 돕습니다.
키보드 탐색
캘린더 피커
| 키 | 동작 |
|---|---|
ArrowLeft | 이전 날짜로 포커스 이동 |
ArrowRight | 다음 날짜로 포커스 이동 |
ArrowUp | 이전 주로 포커스 이동 (같은 요일) |
ArrowDown | 다음 주로 포커스 이동 (같은 요일) |
Enter / Space | 포커스된 날짜 선택 |
Escape | 변경사항 취소 및 팝업 닫기 |
Tab | 다음 포커스 가능한 요소로 이동 (브라우저 기본 동작) |
비활성화된 날짜 건너뛰기: 화살표 키로 탐색할 때 비활성화된 날짜는 자동으로 건너뜁니다. 피커는 이동 방향으로 최대 365일까지 탐색하여 다음 활성화된 날짜를 찾습니다.
자동 월 스크롤: 키보드 포커스가 다른 월의 날짜로 이동하면 캘린더 뷰가 해당 월을 표시하도록 업데이트됩니다.
시간 피커
| 키 | 동작 |
|---|---|
Escape | 변경사항 취소 및 팝업 닫기 |
시간 선택은 클릭/터치 상호작용이 가능한 스크롤 휠 UI를 사용합니다. 스크롤 컬럼은 정확한 값 선택을 위해 scroll-snap을 사용합니다.
ARIA 속성
모든 상호작용 요소는 적절한 ARIA 역할과 속성을 가집니다:
팝업 및 컨테이너
| 요소 | 속성 | 값 |
|---|---|---|
| 팝업 컨테이너 | role | "dialog" |
| 인라인 컨테이너 | role | "group" |
| 컨테이너 | aria-label | 로케일의 플레이스홀더 텍스트 |
| 컨테이너 | aria-activedescendant | 현재 포커스된 날짜 셀의 ID |
트리거 버튼
| 속성 | 값 |
|---|---|
aria-expanded | 팝업이 열려 있을 때 true |
aria-haspopup | "dialog" |
캘린더 그리드
| 요소 | 속성 | 값 |
|---|---|---|
| 그리드 래퍼 | role | "grid" |
| 주(Week) 행 | role | "row" |
| 요일 헤더 셀 | role | "columnheader" |
| 날짜 셀 | role | "gridcell" |
| 날짜 셀 | aria-selected | 선택되었을 때 true |
| 날짜 셀 | aria-current | 셀이 오늘 날짜일 때 "date" |
| 날짜 셀 | aria-label | 포맷된 날짜 문자열 (예: "2026-03-04") |
| 날짜 셀 | disabled | 비활성화된 날짜에 설정됨 (네이티브 HTML 속성) |
탐색 및 드롭다운
| 요소 | 속성 | 값 |
|---|---|---|
| 이전 월 버튼 | aria-label | "Previous month" (locale.prevMonthLabel에서 가져옴) |
| 다음 월 버튼 | aria-label | "Next month" (locale.nextMonthLabel에서 가져옴) |
| 월 드롭다운 | aria-label | "Select month" (locale.selectMonthLabel에서 가져옴) |
| 연도 드롭다운 | aria-label | "Select year" (locale.selectYearLabel에서 가져옴) |
시간 컬럼
| 요소 | 속성 | 값 |
|---|---|---|
| 시(Hour) 컬럼 | role | "listbox" |
| 시(Hour) 컬럼 | aria-orientation | "vertical" |
| 시(Hour) 컬럼 | aria-label | "Hours" (locale.hourLabel에서 가져옴) |
| 분(Minute) 컬럼 | role | "listbox" |
| 분(Minute) 컬럼 | aria-orientation | "vertical" |
| 분(Minute) 컬럼 | aria-label | "Minutes" (locale.minuteLabel에서 가져옴) |
| 초(Second) 컬럼 | role | "listbox" |
| 초(Second) 컬럼 | aria-orientation | "vertical" |
| 초(Second) 컬럼 | aria-label | "Seconds" (locale.secondLabel에서 가져옴) |
| 시간 아이템 | role | "option" (패딩 아이템: "presentation") |
| 시간 아이템 | aria-selected | 아이템이 현재 값일 때 true |
| 오전/오후 토글 | aria-label | 현재 기간 + ”, toggle AM/PM” |
| 지우기 버튼 | aria-label | "Clear" (locale.clear에서 가져옴) |
모든 라벨 문자열은 로케일 시스템을 통해 사용자 정의할 수 있습니다.
포커스 관리
로빙 탭인덱스 (Roving Tabindex)
캘린더 그리드는 로빙 탭인덱스(roving tabindex) 패턴을 사용합니다:
- 현재 포커스된 날짜 셀만
tabIndex={0}을 가집니다 (탭 가능). - 다른 모든 날짜 셀은
tabIndex={-1}을 가집니다 (탭 불가능, 하지만 화살표 키로 포커스 가능). - 즉,
Tab키는 캘린더 그리드 밖(다음 컨트롤)으로 포커스를 이동시키고, 화살표 키는 그리드 내에서 포커스를 이동시킵니다.
팝업 포커스 트래핑
팝업 모드는 @floating-ui/react의 FloatingFocusManager를 사용하여 다음을 수행합니다:
- 팝업이 열려 있는 동안 포커스를 팝업 내에 가둡니다.
- 팝업이 닫힐 때 트리거 버튼으로 포커스를 되돌립니다.
- 팝업에서 배경 콘텐츠로 탭 이동하는 것을 방지합니다.
네이티브 요소
월 및 연도 선택은 기본적으로 키보드 접근이 가능한 네이티브 <select> 요소를 사용합니다. 날짜 셀은 적절한 비활성화 상태를 가진 네이티브 <button> 요소를 사용합니다.
WCAG 2.1 준수
다음 WCAG 2.1 성공 기준을 충족합니다