탭 접근성 개선 리팩토링 기록
2025년 4월 16일
탭 접근성 개선을 위한 리팩토링
Epigram 프로젝트를 진행하면서 탭 컴포넌트에 접근성을 고려하지 않았던 부분을 발견했습니다.
단순히 탭 클릭만으로 전환되던 기존 UI는 스크린 리더나 키보드 사용자에게 불친절한 구조였습니다. 이번 글에서는 접근성 개념 정리부터, 제가 어떤 속성을 어떻게 추가했고, 왜 그렇게 해야 했는지를 정리해보려 합니다.
WAI-ARIA란?
접근성을 위해 WAI-ARIA(Web Accessibility Initiative – Accessible Rich Internet Applications)라는 명세가 존재합니다. 시맨틱 HTML만으로는 부족할 수 있는 동적 UI(탭, 아코디언 등)에 역할(role)과 상태를 명시해줌으로써 보조기술이 화면을 더 잘 이해할 수 있게 해주는 속성들입니다.
Role 속성
role은 요소의 의미(역할)를 명시적으로 정의합니다. 시맨틱 태그를 사용하지 않거나, 커스텀 컴포넌트를 만들 경우 명확히 사용해야 합니다.
탭 UI에서 사용되는 대표적인 역할:
역할 | 설명 |
tablist | 탭 버튼을 묶는 컨테이너의 역할 |
tab | 개별 탭 버튼의 역할 |
tabpanel | 각 탭에 대응하는 콘텐츠 영역의 역할 |
aria-selected
탭 중에서 어떤 탭이 선택된 상태인지를 명시해주는 속성입니다.
<button role="tab" aria-selected="true">홈</button>
<button role="tab" aria-selected="false">프로필</button>
보조기기 사용자에게 “현재 어떤 탭이 선택된 상태인지” 알 수 있게 해주는 중요한 속성입니다.
키보드 접근성: 방향키 이동
웹 접근성 지침에 따라, 탭 컴포넌트는 다음 키보드 조작을 지원해야 합니다:
- → 오른쪽 탭으로 이동
- ← 왼쪽 탭으로 이동
- 포커스된 탭이 자동으로 활성화됨
이 처리를 위해 탭 리스트에 onKeyDown 핸들러를 달아 좌우 방향키로 activeTab을 변경하도록 구현했습니다.
리팩토링 내용 정리
1. TabList컴포넌트
- role="tablist" 속성 추가
- activeTab을 props로 받아 현재 탭 상태를 판단
- 방향키(ArrowRight, ArrowLeft)에 따라 포커스 이동 및 탭 전환
<div role="tablist" onKeyDown={handleKeyDown}>
{/* TabBtns */}
</div>
2. TabBtn 컴포넌트
- role="tab" 추가로 시멘틱 명시
- aria-selected={isActive}로 선택 상태 명시
- tabIndex={isActive ? 0 : -1} 으로 현재 활성 탭만 포커스 가능
- onFocus={() => setActiveTab(index)}로 포커싱만으로도 탭 전환되도록 구현
<button
role="tab"
aria-selected={isActive}
tabIndex={isActive ? 0 : -1}
onFocus={() => setActiveTab(index)}
>
탭명
</button>
개선 결과
항목 | 개선 전 | 개선 후 |
시맨틱 구조 | 없음 | role, aria-*로 명확히 정의 |
키보드 접근성 | 불가능 | 방향키로 탭 전환 가능 |
보조기기 인식 가능 여부 | 불명확 | 스크린 리더가 현재 선택된 탭 인식 가능 |