ARIA 접근성 가이드

역할 · 창

role="dialog"

본문 위에 따로 뜨는 대화상자(창)입니다. 레이어 팝업·모달 창이 여기에 해당하며, HTML <dialog>에 대응합니다.

기초HTML 요소 우선

한눈에 보기

분류
창
대응 HTML
<dialog> (모달은 showModal()로 열기)
이름 정하는 방법
작성자 (author)
이름 필수
예
필수 상위 요소
없음
필수 하위 요소
없음

설명

dialog는 웹 애플리케이션의 주 창(웹 문서 전체) 위에 뜨는 하위 창입니다. 사용자에게 정보를 입력받거나 응답을 요청할 때 씁니다. 흐름을 막고 응답을 받아야 하는 대화상자는 보통 모달(뒤 내용을 조작할 수 없음)이고, 옆에 띄워 두고 본문과 오가며 쓰는 대화상자는 비모달입니다.

HTML <dialog>를 먼저

<dialog> 요소를 showModal()로 열면 브라우저가 다음을 자동으로 처리합니다.

  • 대화상자 밖의 내용을 inert로 만들어 포커스·클릭·화면낭독기 탐색에서 제외
  • 열릴 때 대화상자 안으로 포커스 이동(autofocus가 있으면 그 요소)
  • Esc로 닫기, 최상위 레이어(top layer)에 표시, ::backdrop 제공
  • 닫을 때 열기 전 포커스가 있던 요소로 포커스 복귀(HTML 명세에 포함, 최신 브라우저 지원)

show()로 열면 비모달 대화상자가 됩니다. <dialog>를 쓸 때도 이름(aria-labelledby)은 직접 지정해야 합니다.

ARIA로 만들 때 해야 할 일

  • 이름 필수: 보이는 제목을 aria-labelledby로 연결하거나 aria-label을 줍니다.
  • 설명(선택): 짧은 안내 문구가 있으면 aria-describedby로 연결합니다. 양식·표처럼 구조가 있는 긴 내용은 연결하지 않습니다(한 번에 길게 읽히므로).
  • 모달 표시: aria-modal="true"로 대화상자 밖 내용이 비활성임을 알립니다. 실제로도 밖을 조작할 수 없게(포커스 가두기, 배경 inert) 만들어야 합니다.
  • 포커스 관리: 열 때 안의 요소로 포커스를 옮기고(첫 조작 요소, 또는 내용이 길면 제목 같은 정적 요소에 tabindex="-1"), 닫을 때 연 버튼으로 돌려보냅니다. 명세는 모달·비모달 모두 포커스 가능한 요소를 하나 이상 두라고 권장합니다.
  • 닫기 수단: Esc와 보이는 닫기 버튼을 제공합니다.

주의할 점

  • 여기서 말하는 “애플리케이션”은 application 역할과 무관합니다. 대화상자에 application 역할을 덧씌우지 않습니다.
  • 열려 있는 동안 배경 스크롤을 막고, 확대(200%·400%)했을 때도 대화상자 내용을 모두 볼 수 있게 합니다.
  • 사용자 확인이 필요한 경고라면 alertdialog가 더 정확합니다.

테스터 관점

① 열릴 때 포커스가 대화상자 안으로 가고 “제목, 대화상자”가 읽히는지 ② Tab·Shift+Tab이 밖으로 새지 않는지 ③ 화면낭독기 가상 커서로도 배경 내용이 읽히지 않는지 ④ Esc로 닫히는지 ⑤ 닫은 뒤 포커스가 연 버튼으로 돌아오는지 확인합니다. 포커스 복귀 누락이 가장 흔한 결함입니다.

함께 쓰는 속성

지원 속성

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

키보드 동작

키보드 동작
키동작
Tab대화상자 안의 다음 포커스 가능 요소로 이동합니다. 마지막 요소에서는 첫 요소로 돌아갑니다(모달일 때).
Shift + Tab이전 포커스 가능 요소로 이동합니다. 첫 요소에서는 마지막 요소로 갑니다(모달일 때).
Esc대화상자를 닫고 열기 전 요소로 포커스를 되돌립니다.

사용 예

HTML dialog (권장)

권장HTML
<button type="button" id="open">대출 신청</button>

<dialog id="dlg" aria-labelledby="dlg-title">
  <h2 id="dlg-title">대출 신청</h2>
  <form method="dialog">
    <label><input type="checkbox" name="remind"> 반납일 알림 받기</label>
    <button value="cancel">취소</button>
    <button value="ok">신청</button>
  </form>
</dialog>

<script>
  const dlg = document.getElementById('dlg');
  document.getElementById('open').addEventListener('click', () => dlg.showModal());
</script>

<form method="dialog"> 안의 버튼은 대화상자를 닫고, 그 값이 dlg.returnValue에 남습니다.

div로 만든 모달 대화상자

HTML
<div role="dialog" aria-modal="true" aria-labelledby="d-t" aria-describedby="d-d">
  <h2 id="d-t">대출 신청</h2>
  <p id="d-d">어린 왕자를 14일 동안 대출합니다.</p>
  …
  <button type="button">닫기</button>
</div>

포커스 이동·가두기·Esc 닫기·포커스 복귀는 스크립트로 직접 구현해야 합니다.

이름도 포커스 관리도 없는 레이어 (비권장)

비권장HTML
<div class="layer-popup" style="display:block">
  <div class="title">대출 신청</div>
  …
  <span class="close" onclick="closeLayer()">X</span>
</div>

대화상자로 인식되지 않고, 닫기 요소는 키보드로 조작할 수 없으며, 포커스가 그대로 배경에 남습니다.

직접 해 보기

“대출 신청”을 눌러 보세요. 포커스가 대화상자 안으로 이동하고, Tab은 안에서만 돌며, Esc나 버튼으로 닫으면 포커스가 원래 버튼으로 돌아옵니다. 결과는 아래 상태 메시지로 알려 줍니다.

화면낭독기에서는

화면낭독기 안내 예시 (표현은 화면낭독기·브라우저·버전에 따라 조금씩 다릅니다)
상황들리는 안내 (예)
대화상자가 열림 (포커스가 체크박스로 이동)대출 신청, 대화상자, 어린 왕자를 14일 동안 대출합니다. 반납일 하루 전에 알림 받기, 체크 상자, 체크 안 됨
“신청”으로 닫음대출 신청, 버튼 … 대출을 신청했습니다. 반납일은 14일 뒤입니다.

사용 지침

이렇게 쓰세요

  • 가능하면 <dialog>와 showModal()을 씁니다.
  • 제목을 aria-labelledby로 연결해 이름을 줍니다.
  • 열 때 안으로, 닫을 때 연 버튼으로 포커스를 옮깁니다.
  • Esc와 보이는 닫기 버튼을 모두 제공합니다.

이렇게 쓰지 마세요

  • aria-modal="true"만 주고 실제 포커스 가두기·배경 비활성화를 빠뜨리지 않습니다.
  • 긴 양식 전체를 aria-describedby로 연결하지 않습니다.
  • 닫기를 키보드로 조작할 수 없는 <span>·<div>로 만들지 않습니다.

이 역할을 쓰는 패턴

참고 자료