역할 · 위젯
role="button"
누르면 동작을 실행하는 버튼입니다. aria-pressed를 더하면 켜고 끄는 토글 버튼이 됩니다.
한눈에 보기
- 분류
- 위젯
- 대응 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에는 역할·포커스·키보드 처리를 모두 더해야 합니다.
<!-- 권장: 기본 기능이 모두 들어 있습니다 -->
<button type="button">저장</button>
<!-- 꼭 필요할 때만: 역할, 포커스, 키보드 처리를 직접 넣어야 합니다 -->
<div role="button" tabindex="0">저장</div>직접 만든 버튼의 키보드 처리
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로 알리고, 이름은 그대로 둡니다.
<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에 가상 커서로 이동 | div (역할 없음) (버튼이라는 말 없이 텍스트만 읽음) |
사용 지침
이렇게 쓰세요
- 가능하면
<button type="button">을 씁니다. 폼 안에서type을 생략하면 제출 버튼이 되니 주의합니다. - 직접 만든 버튼에는
tabindex="0", Enter·Space 처리, 보이는 포커스 표시를 모두 넣습니다. - 아이콘 버튼에는 동작을 설명하는 이름을 붙입니다. 예:
aria-label="장바구니에 담기". - 토글 버튼은
aria-pressed로 상태를 알리고 이름은 고정합니다.
이렇게 쓰지 마세요
- 페이지 이동에 버튼을 쓰지 않습니다. 이동은 링크(
<a href>)입니다. - 버튼 안에 링크·입력란·다른 버튼을 넣지 않습니다. 자식은 모두 표현용으로 바뀝니다.
<a href="#">에role="button"만 붙이고 Space 처리를 빠뜨리지 않습니다.aria-pressed와aria-expanded를 같은 버튼에 함께 쓰지 않습니다. 의미가 다릅니다.
관련 역할·패턴
이 역할을 쓰는 패턴