ARIA 접근성 가이드

WCAG 2.2 · 4. 견고성 · 4.1 호환성

4.1.2 이름, 역할, 값

Name, Role, Value

모든 사용자 인터페이스 구성 요소는 이름과 역할을 프로그램이 알 수 있어야 하고, 사용자가 바꾸는 상태·속성·값과 그 변화도 보조 기술에 전달되어야 합니다. ARIA가 해결하려는 문제의 핵심입니다.

수준 AWCAG 2.0

한눈에 보기

성공 기준
4.1.2 이름, 역할, 값
수준
수준 A
원칙
4. 견고성
지침
4.1 호환성
도입
WCAG 2.0

요구 사항

폼 요소, 링크, 스크립트로 만든 구성 요소를 포함한 모든 사용자 인터페이스 구성 요소에 대해 다음이 성립해야 합니다.

  • 이름(name)과 역할(role)을 프로그램이 판별할 수 있습니다. — "무엇이라고 부르는가", "무엇인가(버튼, 체크박스, 탭…)"
  • 사용자가 설정할 수 있는 상태(state), 속성(property), 값(value)을 프로그램이 설정할 수 있습니다. — 체크됨, 펼쳐짐, 선택됨, 슬라이더 값 등
  • 이 항목들이 바뀌었다는 알림이 보조 기술을 포함한 사용자 에이전트에 전달됩니다.

원문 주석에 따르면 이 기준은 주로 직접 사용자 인터페이스 구성 요소를 개발하거나 스크립트로 만드는 작성자를 위한 것입니다. 표준 HTML 컨트롤(<button>, <input>, <select>, <a href>)을 명세대로 쓰면 브라우저가 이름·역할·상태를 자동으로 제공하므로 대부분 충족됩니다. 문제는 <div>, <span>으로 만든 커스텀 위젯입니다. 이때 role, aria-* 속성으로 정보를 직접 제공해야 합니다.

각 개념에 대한 자세한 설명은 이름·역할·값 가이드와 접근 가능한 이름 가이드를 참고하세요.

왜 필요한가요

화면낭독기, 음성 인식, 스위치 제어 같은 보조 기술은 화면의 모양을 보지 않습니다. 브라우저가 운영체제 접근성 API로 넘겨 주는 정보(접근성 트리)만 사용합니다. 겉모습이 버튼이어도 <div>라면 보조 기술에는 "그냥 텍스트"이고, 펼침 메뉴가 열려도 aria-expanded가 바뀌지 않으면 열렸는지 알 수 없습니다.

  • 이름이 없으면: 아이콘 버튼이 "버튼"이라고만 읽혀 무슨 기능인지 모릅니다.
  • 역할이 없으면: 누를 수 있는 요소인지 몰라 지나치며, 음성 인식 사용자는 "버튼 클릭"으로 실행할 수 없습니다.
  • 상태가 없으면: 체크박스가 선택됐는지, 탭이 선택됐는지, 메뉴가 펼쳐졌는지 알 수 없습니다.

도움받는 사용자

  • 시각장애인(화면낭독기 사용자)
  • 음성 인식 사용자(이름으로 컨트롤을 호출)
  • 스위치·대체 입력 장치 사용자
  • 점자 단말기 사용자

적용 방법

1. 가능하면 네이티브 HTML 요소를 씁니다

ARIA의 첫 번째 규칙은 "같은 의미의 HTML 요소가 있으면 그것을 쓴다"입니다. <button>은 이름(콘텐츠), 역할(button), 키보드 동작, 포커스를 모두 기본으로 갖습니다.

비권장div로 만든 버튼
<div class="btn" onclick="save()">저장</div>
권장네이티브 버튼
<button type="button" onclick="save()">저장</button>

2. 커스텀 위젯에는 역할·이름·상태를 모두 제공합니다

어쩔 수 없이 커스텀 요소를 쓴다면 role, 접근 가능한 이름, 필요한 상태 속성, tabindex, 키보드 동작을 모두 구현해야 합니다. 역할만 붙이면 키보드 동작이 따라오지 않습니다.

커스텀 체크박스 — 역할·이름·상태
<span role="checkbox" tabindex="0" aria-checked="false"
      aria-labelledby="agree-label" id="agree"></span>
<span id="agree-label">이용 약관에 동의합니다</span>
JavaScript
var box = document.getElementById('agree');
function toggle() {
  var on = box.getAttribute('aria-checked') === 'true';
  box.setAttribute('aria-checked', String(!on));   // 상태 변화 → 보조 기술에 전달
}
box.addEventListener('click', toggle);
box.addEventListener('keydown', function (e) {
  if (e.key === ' ') { e.preventDefault(); toggle(); }
});

자세한 구현은 체크박스 패턴을 참고하세요. 네이티브 <input type="checkbox">를 쓰면 이 코드가 전부 필요 없습니다.

3. 아이콘만 있는 컨트롤에 이름을 줍니다

비권장이름 없는 아이콘 버튼
<button type="button"><svg>...</svg></button>
권장aria-label로 이름 제공
<button type="button" aria-label="검색">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

4. 상태가 바뀌면 속성도 함께 바꿉니다

화면 상태와 ARIA 상태가 항상 같아야 합니다. 보이는 모양만 바꾸고 속성을 갱신하지 않는 것이 가장 흔한 실패입니다.

상태를 가진 대표 위젯
<!-- 펼침 버튼 (Disclosure) -->
<button type="button" aria-expanded="false" aria-controls="faq1">배송은 얼마나 걸리나요?</button>
<div id="faq1" hidden>주문 후 2~3일 안에 도착합니다.</div>

<!-- 토글 버튼 -->
<button type="button" aria-pressed="false">음소거</button>

<!-- 탭 -->
<div role="tablist" aria-label="상품 정보">
  <button role="tab" id="t1" aria-selected="true" aria-controls="p1">상세 정보</button>
  <button role="tab" id="t2" aria-selected="false" aria-controls="p2" tabindex="-1">리뷰</button>
</div>
<div role="tabpanel" id="p1" aria-labelledby="t1">...</div>
펼침 상태 동기화
btn.addEventListener('click', function () {
  var open = btn.getAttribute('aria-expanded') === 'true';
  btn.setAttribute('aria-expanded', String(!open));
  panel.hidden = open;
});

5. 값을 가진 위젯은 값을 노출합니다

커스텀 슬라이더
<div role="slider" tabindex="0" aria-label="음량"
     aria-valuemin="0" aria-valuemax="100" aria-valuenow="40"
     aria-valuetext="40퍼센트"></div>

가능하면 <input type="range">를 쓰고, 커스텀 구현은 슬라이더 패턴을 참고합니다.

관련 패턴

버튼, 펼침, 아코디언, 탭, 대화상자, 메뉴 버튼, 콤보박스, 리스트박스, 라디오 그룹, 스위치, 슬라이더 패턴이 모두 이 기준을 지키는 방법을 다룹니다.

사례

span으로 만든 링크

비권장HTML
<span class="link" onclick="location.href='/notice'">공지사항</span>

역할이 없어 링크로 인식되지 않고, 포커스도 받지 못합니다. <a href="/notice">를 씁니다.

포커스 가능한 요소를 aria-hidden으로 숨김

비권장HTML
<div aria-hidden="true">
  <button type="button">닫기</button>
</div>

키보드로 포커스는 가지만 화면낭독기에는 이름·역할이 전달되지 않습니다. 콘텐츠 숨기기 가이드를 참고하세요.

모양만 바뀌는 선택 상태

비권장HTML
<li class="tab is-active">상세 정보</li>
<li class="tab">리뷰</li>

탭 역할과 aria-selected가 없어 어떤 탭이 선택됐는지 알 수 없습니다.

보이는 이름과 접근 가능한 이름 일치

권장HTML
<button type="button" aria-describedby="del-hint">삭제</button>
<p id="del-hint">삭제한 항목은 복구할 수 없습니다.</p>

이름은 보이는 텍스트 "삭제"를 그대로 쓰고, 추가 정보는 설명으로 연결합니다(2.5.3 레이블과 이름도 함께 충족).

자주 하는 실수

  • <div>, <span>에 클릭 이벤트만 붙여 버튼·링크를 만들고 역할을 주지 않습니다.
  • 아이콘 버튼, 이미지 링크, 레이블 없는 입력 필드처럼 접근 가능한 이름이 비어 있습니다.
  • 펼침·선택·체크 상태가 화면에서는 바뀌는데 aria-expanded, aria-selected, aria-checked는 그대로입니다.
  • 포커스를 받을 수 있는 요소를 aria-hidden="true" 영역 안에 두거나, role="presentation"으로 의미를 지웁니다.

검사 방법

  • 브라우저 개발자 도구의 접근성 패널(Chrome Accessibility, Firefox 접근성 검사기)에서 각 컨트롤의 이름(Name)과 역할(Role)을 확인합니다.
  • 커스텀 위젯을 조작하며 상태 속성(aria-expanded, aria-checked, aria-selected, aria-valuenow 등)이 화면 상태와 함께 바뀌는지 확인합니다.
  • 화면낭독기(NVDA 등)로 각 컨트롤에 포커스해 "이름, 역할, 상태"가 읽히고, 조작 후 바뀐 상태가 안내되는지 확인합니다.
  • axe 같은 자동 검사 도구로 이름 없는 버튼·링크·폼 컨트롤, 잘못된 ARIA 속성을 찾습니다.

관련 ARIA

다른 지침의 대응 항목

참고 자료