ARIA 접근성 가이드

역할 · 위젯

role="button"

누르면 동작을 실행하는 버튼입니다. aria-pressed를 더하면 켜고 끄는 토글 버튼이 됩니다.

기초HTML 요소 우선

한눈에 보기

분류
위젯
대응 HTML
<button>, <input type="button">, <input type="submit">, <input type="reset">, <input type="image">
이름 정하는 방법
콘텐츠, 작성자
이름 필수
예
필수 상위 요소
없음
필수 하위 요소
없음

설명

button 역할은 사용자가 눌러서 동작을 실행하는 요소입니다. 폼 제출, 대화상자 열기, 패널 펼치기, 항목 삭제처럼 “현재 페이지에서 무언가를 한다”면 버튼입니다. 다른 페이지나 같은 페이지의 다른 위치로 이동한다면 link를 씁니다.

HTML의 <button>은 이 역할을 기본으로 가지고 있고, 포커스 이동, Enter·Space 실행, 비활성화(disabled), 폼 제출까지 브라우저가 처리합니다. <div role="button">을 만들면 이 모든 것을 직접 구현해야 하므로, 가능한 한 <button>을 씁니다. 이것이 ARIA 사용 첫 번째 규칙입니다.

버튼의 세 가지 형태

  • 일반 버튼 — 누르면 동작을 실행합니다.
  • 토글 버튼 — aria-pressed로 눌림(켜짐)/안 눌림 상태를 가집니다. 예: 굵게(B), 음소거. 상태가 바뀌어도 이름은 바꾸지 않습니다. “음소거” 버튼의 이름을 “음소거 해제”로 바꾸면서 동시에 aria-pressed를 쓰면 상태를 두 번 말하는 셈이 됩니다.
  • 메뉴 버튼·펼침 버튼 — aria-haspopup과 aria-expanded로 메뉴나 패널을 연다는 것과 열림 상태를 알립니다.

자식 요소는 모두 표현용(presentational)이 됩니다

button은 Children Presentational: True입니다. 버튼 안의 제목·목록·링크 같은 의미는 접근성 트리에서 사라지고 텍스트만 남습니다. 버튼 안에 링크나 다른 버튼처럼 상호작용 요소를 넣지 마세요.

테스터 관점

  • Tab으로 포커스가 가는지, Enter와 Space 둘 다로 실행되는지 확인합니다. 둘 중 하나만 되면 결함입니다.
  • 아이콘만 있는 버튼에 접근 가능한 이름(aria-label, 숨긴 텍스트 등)이 있는지 확인합니다.
  • 클릭 시 페이지를 이동하는데 버튼으로 표시되거나, 반대로 버튼처럼 동작하는데 링크로 표시되는 경우를 찾습니다.
  • aria-disabled="true"인 버튼이 실제로 동작을 막는지 확인합니다. ARIA 속성은 동작을 바꾸지 않습니다.

함께 쓰는 속성

지원 속성

전역 속성(이름·설명 등)은 모든 역할에 쓸 수 있어 생략했습니다.

키보드 동작

키보드 동작
키동작
Enter버튼을 실행합니다. 네이티브 <button>은 키를 누를 때(keydown) 실행됩니다.
Space버튼을 실행합니다. 네이티브 <button>은 키를 뗄 때(keyup) 실행되며, 기본 스크롤 동작은 일어나지 않습니다.
Tab버튼으로 포커스를 옮깁니다. 직접 만든 버튼은 tabindex="0"이 있어야 합니다.

사용 예

HTML 버튼과 ARIA 버튼 비교

같은 결과를 내려면 div에는 역할·포커스·키보드 처리를 모두 더해야 합니다.

HTML
<!-- 권장: 기본 기능이 모두 들어 있습니다 -->
<button type="button">저장</button>

<!-- 꼭 필요할 때만: 역할, 포커스, 키보드 처리를 직접 넣어야 합니다 -->
<div role="button" tabindex="0">저장</div>

직접 만든 버튼의 키보드 처리

div role="button" 키보드 처리
el.addEventListener('keydown', function (e) {
  if (e.key === 'Enter') { e.preventDefault(); run(); }
  if (e.key === ' ') e.preventDefault();   // 스크롤 막기
});
el.addEventListener('keyup', function (e) {
  if (e.key === ' ') run();                 // Space는 뗄 때 실행
});
el.addEventListener('click', run);

토글 버튼

상태는 aria-pressed로 알리고, 이름은 그대로 둡니다.

HTML
<button type="button" aria-pressed="false" id="mute">음소거</button>
<script>
  var b = document.getElementById('mute');
  b.addEventListener('click', function () {
    var on = b.getAttribute('aria-pressed') === 'true';
    b.setAttribute('aria-pressed', String(!on));
  });
</script>

이름과 상태를 함께 바꾸는 실수

비권장비권장: 상태가 두 번 전달됨
<button type="button" aria-pressed="true">음소거 해제</button>
<!-- “음소거 해제, 토글 버튼, 눌림” → 지금 음소거인지 아닌지 헷갈립니다 -->

직접 해 보기

세 버튼을 마우스와 키보드(Tab, Enter, Space)로 각각 눌러 보세요. 세 번째 div는 역할·tabindex·키 처리가 없어 Tab으로 도달할 수 없습니다. 마지막 토글 버튼을 누르면 aria-pressed 값이 바뀝니다.

div role="button"
div (역할 없음)

아직 누른 버튼이 없습니다.

화면낭독기에서는

화면낭독기 안내 예시 (표현은 화면낭독기·브라우저·버전에 따라 조금씩 다릅니다)
상황들리는 안내 (예)
버튼에 포커스저장, 버튼
토글 버튼(꺼짐)에 포커스굵게, 토글 버튼, 안 눌림
토글 버튼을 눌러 켬눌림
메뉴 버튼에 포커스보기, 메뉴 버튼, 축소됨
역할 없는 div에 가상 커서로 이동div (역할 없음) (버튼이라는 말 없이 텍스트만 읽음)

사용 지침

이렇게 쓰세요

  • 가능하면 <button type="button">을 씁니다. 폼 안에서 type을 생략하면 제출 버튼이 되니 주의합니다.
  • 직접 만든 버튼에는 tabindex="0", Enter·Space 처리, 보이는 포커스 표시를 모두 넣습니다.
  • 아이콘 버튼에는 동작을 설명하는 이름을 붙입니다. 예: aria-label="장바구니에 담기".
  • 토글 버튼은 aria-pressed로 상태를 알리고 이름은 고정합니다.

이렇게 쓰지 마세요

  • 페이지 이동에 버튼을 쓰지 않습니다. 이동은 링크(<a href>)입니다.
  • 버튼 안에 링크·입력란·다른 버튼을 넣지 않습니다. 자식은 모두 표현용으로 바뀝니다.
  • <a href="#">에 role="button"만 붙이고 Space 처리를 빠뜨리지 않습니다.
  • aria-pressed와 aria-expanded를 같은 버튼에 함께 쓰지 않습니다. 의미가 다릅니다.

이 역할을 쓰는 패턴

참고 자료