동적 접근성

아코디언 UI에서 aria-expanded가 작동하지 않는 이유: 토글 버튼 상태 동기화와 키보드 접근성 설계

WCAG 2.2 성공 기준 4.1.2(Name, Role, Value)와 1.3.1(Info and Relationships)에 따라, 아코디언 및 접힘/펼침 UI 구현 시 div 클릭 오용을 시정하고 aria-expanded 및 aria-controls 동적 속성으로 접힘 상태를 보조공학기기에 표준에 맞게 노출하는 실무 기법을 분석합니다.

작성자 서호영 (기획·개발·콘텐츠 검토) · 발행 · 수정 · 읽기 11분

아코디언 토글 버튼의 aria-expanded 상태 전달 비교div 클릭만 구현한 경우 스크린리더가 접힘/펼침 상태를 알 수 없습니다. button 요소와 aria-expanded 속성으로 상태를 동기화해야 합니다.WCAG 2.2 4.1.2 이름·역할·값(Name, Role, Value) 아코디언 상태<div onClick> 단순 시각 토글자주 묻는 질문 1 ▼FAIL (4.1.2)접근성 트리: "자주 묻는 질문 1, 그룹" (상태 미연결)키보드 Enter/Space 조작 불가, 닫힘 여부 인지 불가<button aria-expanded> 접근성 트리<button aria-expanded="true"> ▲PASS (AA)접근성 트리: "자주 묻는 질문 1, 버튼, 축소됨/확장됨" 노출aria-controls로 본문 패널 id와 명시적 연결 지원
자체 검증 도식: 아코디언 토글 버튼은 aria-expanded="true|false" 및 aria-controls="panel-id"를 동기화하여 보조기술이 상태를 해석할 수 있는 구조를 제공합니다.

실무 검증 기록

마크업 및 접근성 트리 대조

본 기록은 공개 fixture와 재현 조건을 기준으로 정리한 기술 설명입니다. 실제 브라우저·스크린리더 조합의 동작은 별도 수동 검토가 필요합니다.

접근성 기술 검증 상세 내역
검증 상태공개 fixture 기반 재현 완료
검증 기준공개 fixture 및 재현 조건
검증 범위아코디언 토글 버튼 aria-expanded 상태 동기화 및 키보드 조작 검증 및 명시된 입력값에 한정
수동 확인실제 브라우저·키보드·스크린리더 환경에서 별도 확인 필요
fixture에서 확인한 기대 결과[실패 상태] 버튼 상태와 실제 panel 표시가 불일치 ➔ [수정 목표] 토글·관계·키보드 동작을 같은 이벤트로 동기화

검증에 사용된 실제 픽스처 / 재현 조건

닫힌 panel, aria-expanded=false, hidden 상태
검증 범위 및 한계
  • 아코디언 헤더를 H2~H4 제목 태그로 감싸는 구조적 마크업 정합성
  • 여러 아코디언이 동시에 열릴 수 있는 다중 모드 vs 단일 모드 동작

주장과 직결된 W3C 공식 규격

자주 묻는 질문(FAQ), 상세 사양 보기, 모바일 내비게이션 드로어 등에서 광범위하게 활용되는 아코디언(Accordion) 컴포넌트는 한정된 화면 공간을 효율적으로 활용할 수 있는 대표적인 접힘/펼침 UI입니다. 그러나 수많은 웹사이트에서 아코디언을 구현할 때 <div>나 <span> 태그에 단순히 onClick 이벤트만 걸어두거나, 토글 상태를 시각적인 화살표 회전(CSS transform)으로만 표현하고 보조공학에는 아무런 상태 정보를 전달하지 않는 치명적인 접근성 오류를 범하고 있습니다. 이로 인해 스크린리더를 사용하는 시각장애인은 해당 영역이 클릭 가능한 버튼인지조차 알 수 없으며, 클릭한 뒤 내용이 펼쳐졌는지 접혔는지 전혀 인지할 수 없습니다. 이 글에서는 W3C WAI-ARIA APG(Authoring Practices Guide) 표준에 부합하는 아코디언 마크업 구조와 aria-expanded 상태 동기화 기법, 그리고 완전한 키보드 인터랙션 설계법을 상세히 설명합니다.

흔히 발생하는 3대 아코디언 마크업 안티패턴

웹 접근성 감사 현장에서 발견되는 아코디언 구현의 문제점은 주로 시맨틱 태그의 부재와 상태 정보의 누락에서 비롯됩니다.

첫 번째 안티패턴은 '비대화형 요소(Non-interactive elements)의 오용'입니다. <div class='accordion-header' onClick={...}> 형태로 마크업하면, 마우스 사용자는 클릭할 수 있지만 키보드 사용자는 Tab 키로 해당 요소에 접근조차 할 수 없습니다. 임시방편으로 tabindex='0'을 추가하더라도, 스크린리더는 이를 여전히 단순 텍스트나 그룹으로 인식할 뿐 '버튼(Button)'이라는 역할을 낭독하지 않습니다.

두 번째 안티패턴은 'aria-expanded 속성의 누락 또는 하드코딩'입니다. 패널이 펼쳐지거나 접힐 때 버튼의 aria-expanded 속성값을 자바스크립트로 true/false 동적 갱신하지 않으면, 보조공학 사용자는 현재 내용이 화면에 노출되어 있는지 전혀 알 수 없습니다.

세 번째 안티패턴은 '숨겨진 패널의 키보드 초점 방치'입니다. 아코디언이 접혀 있을 때 CSS opacity: 0이나 height: 0으로만 시각적으로 감추고 display: none이나 visibility: hidden을 주지 않으면, 접혀 있는 패널 내부의 링크나 버튼으로 키보드 포커스가 새어 들어가는 현상이 발생합니다.

W3C 표준 권고 아코디언 4대 핵심 마크업 규칙

W3C WAI-ARIA APG 표준 아코디언 패턴을 만족하기 위해서는 다음 4가지 핵심 구조를 엄격히 준수해야 합니다.

  • 1. 헤딩 요소 내부에 버튼 배치: 아코디언의 각 헤더는 문서 계층 구조에 맞는 제목 태그(<h3> 등)로 감싸고, 그 내부에 네이티브 <button> 요소를 배치해야 합니다. 이를 통해 스크린리더 사용자가 헤딩 탐색(H 단축키)으로 아코디언 항목들을 신속하게 건너뛰며 탐색할 수 있습니다.
  • 2. aria-expanded 상태의 실시간 동기화: 트리거 버튼에 aria-expanded='false'(접힘) 또는 aria-expanded='true'(펼침) 속성을 선언하고, 리액트나 뷰의 상태(state) 변화와 정확히 동기화시킵니다.
  • 3. aria-controls와 id 매핑: 트리거 버튼의 aria-controls 속성에 제어 대상인 콘텐츠 패널 컨테이너의 고유 id를 연결합니다. 보조공학 사용자가 버튼에서 연결된 패널 영역으로 즉시 가상 커서를 이동할 수 있는 단서를 제공합니다.
  • 4. 패널의 완전한 숨김 처리: 접힌 상태의 패널 컨테이너에는 hidden HTML 속성이나 CSS display: none을 부여하여, 화면 낭독 및 키보드 초점 대상에서 물리적으로 완벽히 제외해야 합니다.

키보드 인터랙션(Enter, Space, Arrow Keys) 실무 구현

아코디언 컴포넌트의 접근성은 마우스뿐만 아니라 완전한 키보드 조작성을 갖추었을 때 완성됩니다.

기본적으로 트리거 요소로 네이티브 <button>을 사용하면 Enter 키와 Space 키를 통한 토글 동작은 브라우저가 자체적으로 완벽하게 지원합니다. 여기에 더해 W3C APG 권고안은 다중 아코디언 목록에서 효율적인 탐색을 위해 방향키 인터랙션을 권장합니다. 아코디언 헤더에 포커스가 있을 때 아래쪽 화살표(ArrowDown) 키를 누르면 다음 아코디언 헤더로, 위쪽 화살표(ArrowUp) 키를 누르면 이전 아코디언 헤더로 초점이 이동해야 합니다.

또한 Home 키를 누르면 목록의 첫 번째 아코디언 헤더로, End 키를 누르면 마지막 아코디언 헤더로 즉시 이동하는 단축키 처리를 자바스크립트 onKeyDown 핸들러로 보완하면, 수십 개의 FAQ 목록을 탐색해야 하는 키보드 사용자의 이동 피로도를 획기적으로 낮출 수 있습니다.

CSS 트랜지션 애니메이션과 접근성의 공존 전략

많은 프론트엔드 개발자가 부드러운 슬라이드 다운/업 애니메이션을 구현하기 위해 display: none 대신 max-height와 transition을 활용합니다. 그러나 애니메이션이 끝난 후에도 패널이 display: none 되지 않으면, 접힌 상태에서도 내부 텍스트가 스크린리더 가상 커서에 잡히는 부작용이 생깁니다.

가장 성숙한 해결책은 transitionend 이벤트를 활용하거나, 최신 CSS의 @starting-style 및 transition-behavior: allow-discrete 속성을 활용하여 display 속성의 변화를 애니메이션과 결합하는 것입니다. 애니메이션이 진행 중일 때만 요소를 노출하고, 완전히 닫히는 순간 display: none(또는 hidden 속성)을 적용함으로써, 화려한 시각적 UX와 완벽한 보조공학 접근성을 동시에 달성할 수 있습니다.

W3C ARIA APG 규격에 따른 아코디언 키보드 상호작용 표준 설계

아코디언 컴포넌트는 단순히 마우스 클릭으로 패널을 열고 닫는 기능을 넘어, 전적인 키보드 내비게이션을 보장해야 합니다. W3C ARIA Authoring Practices Guide(APG)는 아코디언 헤더에 대해 Enter/Space(열기/닫기), Down Arrow(다음 헤더), Up Arrow(이전 헤더), Home/End(첫/마지막 헤더) 탐색을 공식 규격으로 권장합니다.

실무에서 자주 발견되는 결함은 아코디언 헤더 자체를 <div>에 onClick만 달아 구현하여 Tab 키로 진입조차 불가능하거나, 화살표 키 탐색이 전혀 구현되어 있지 않아 모든 패널을 통과하려면 수십 번의 Tab 키를 연타해야 하는 사용성 문제입니다.

  • Enter / Space 키: 현재 포커스된 아코디언 헤더의 확장/축소 토글 및 aria-expanded 동기화
  • Down / Up 화살표 키: 인접 아코디언 헤더로 포커스 즉시 이동 (패널 내부 콘텐츠 건너뜀)
  • Home / End 키: 목록의 최상단 첫 번째 헤더 및 최하단 마지막 헤더로 즉시 포커스 도약

CSS 높이 트랜지션 애니메이션과 접근성 트리 노출의 비동기 동기화

부드러운 열림 효과를 위해 CSS transition을 적용할 때, 닫힌 상태의 패널을 DOM에 어떻게 둘 것인가가 접근성의 핵심 관건입니다. 패널이 시각적으로만 접혀 있고 hidden 속성이 적용되지 않았다면 보조공학 사용자가 탐색할 때 닫힌 패널의 내용이 그대로 낭독되는 혼란이 발생합니다.

반대로 닫는 애니메이션이 진행되는 도중에 즉시 display: none을 줘버리면 부드러운 애니메이션이 뚝 끊기게 됩니다. transitionend 이벤트 핸들러를 활용하여 애니메이션 완료 시점에 hidden 속성을 안전하게 동기화해야 합니다.

  • 열림 시작 시점: hidden 속성을 즉시 제거하고 애니메이션 클래스(expanded) 활성화
  • 닫힘 완료 시점: onTransitionEnd 이벤트 수신 후 hidden 속성을 부여하여 접근성 트리에서 안전하게 격리
  • 초점 보호: 패널이 닫힐 때 패널 내부에 머물던 포커스를 상위 아코디언 트리거 버튼으로 안전하게 회수

흔한 마크업 안티패턴과 올바른 예방책

잘못된 마크업 패턴올바른 접근성 구현
<div onclick='toggle()'>로 아코디언 헤더를 만들고 aria-expanded 속성을 부여하지 않는 경우네이티브 <button> 요소를 사용하고 클릭/키보드 이벤트 시 aria-expanded='true|false'를 동기화합니다.
다중 아코디언에서 한 패널이 닫힐 때 다른 패널의 aria-expanded 상태를 갱신하지 않는 경우단일 오픈 모드일 경우 기존에 열려 있던 버튼의 aria-expanded를 'false'로 함께 업데이트합니다.

보조공학 낭독 및 브라우저 파싱 한계

  • div 태그에 클릭 이벤트만 부여하고 키보드 리스너(onKeyDown)나 button 요소를 사용하지 않으면 키보드 전용 사용자는 조작 자체가 불가능합니다.
  • 아코디언 패널이 닫혀 있을 때는 내부 링크/버튼이 탭 키에 걸리지 않도록 display:none 또는 hidden 처리를 해야 합니다.

주요 공식 상세 규격

규격 검토 기준일 2026-10-05

작성 및 검토 책임 정보

  • 작성자: 서호영
  • 실제 수행 역할: 기획·개발·콘텐츠 검토
  • 최초 작성일:
  • 최종 수정일:
  • 검증 기준: 공개 fixture 및 재현 조건

네이티브 HTML, ARIA 명세, 브라우저 및 스크린리더 조합에 따라 실제 보조공학 동작은 차이가 발생할 수 있습니다. 오류를 발견하셨거나 검증 데이터에 보완이 필요한 경우 오류 제보 및 문의 또는 liebe2460@naver.com로 알려주시면 사실 확인 후 정정합니다.