역할 · 복합 위젯
role="menu"
명령이나 설정을 고르는 메뉴 항목 목록입니다. 보통 메뉴 버튼이나 메뉴 막대에서 팝업으로 열립니다.
한눈에 보기
- 분류
- 복합 위젯
- 대응 HTML
- 없음 (HTML
<menu>는 목록list역할입니다) - 이름 정하는 방법
- 작성자
- 이름 필수
- 아니요
- 필수 상위 요소
- 없음
- 필수 하위 요소
menuitemmenuitemcheckboxmenuitemradiogroup
설명
menu는 데스크톱 프로그램의 메뉴처럼 동작이나 설정을 고르는 목록입니다. 하위 요소는 menuitem, menuitemcheckbox, menuitemradio이며, 이 항목들을 묶는 group도 넣을 수 있습니다. 항목 사이 구분선은 separator를 씁니다. aria-orientation의 기본값은 세로입니다.
메뉴는 대개 button(메뉴 버튼, aria-haspopup="menu" + aria-expanded), menubar의 항목, 또는 오른쪽 클릭(컨텍스트 메뉴)으로 열립니다. 열리면 포커스가 메뉴 안 항목으로 이동하고, 닫히면 연 요소로 돌아가야 합니다. 이름은 필수는 아니지만 aria-labelledby로 메뉴를 연 버튼을 가리키면 좋습니다.
메뉴 역할이 필요 없는 경우가 많습니다
“메뉴”라고 부르는 UI 대부분은 ARIA menu가 아닙니다.
- 사이트 내비게이션 드롭다운 →
<nav>+ 디스클로저 버튼(aria-expanded) + 링크 목록 - 값 하나를 고르는 드롭다운 →
<select>또는combobox/listbox - 버튼 몇 개를 묶은 막대 →
toolbar
메뉴 역할을 쓰면 화면낭독기는 앱 메뉴 모드로 바뀌고 가상 커서 탐색이 제한됩니다. APG 키보드 규칙을 모두 구현할 수 있을 때만 씁니다.
테스터 관점
- 메뉴가 열리면 첫 항목에 포커스가 가는지, Esc와 Tab으로 닫히는지 확인합니다.
- 메뉴 버튼의
aria-expanded가 열림/닫힘과 일치하는지 확인합니다. - 메뉴 안에 메뉴 항목이 아닌 요소(일반 링크, 텍스트)가 섞여 있지 않은지 확인합니다.
함께 쓰는 속성
지원 속성
전역 속성(이름·설명 등)은 모든 역할에 쓸 수 있어 생략했습니다.
키보드 동작
| 키 | 동작 |
|---|---|
| Enter | (메뉴 버튼) 메뉴를 열고 첫 항목으로 이동합니다. (메뉴 항목) 실행하고 메뉴를 닫거나, 하위 메뉴를 엽니다. |
| Space | (메뉴 버튼) 메뉴를 엽니다. (체크·라디오 항목) 상태를 바꿉니다. |
| ↓ | (메뉴 버튼, 선택 사항) 메뉴를 열고 첫 항목으로 이동합니다. (메뉴 안) 다음 항목으로 이동하며, 끝에서 처음으로 순환할 수 있습니다. |
| ↑ | (메뉴 버튼, 선택 사항) 메뉴를 열고 마지막 항목으로 이동합니다. (메뉴 안) 이전 항목으로 이동합니다. |
| → | 하위 메뉴가 있는 항목에서 하위 메뉴를 열고 첫 항목으로 이동합니다. |
| ← | 하위 메뉴 안에서 하위 메뉴를 닫고 부모 항목으로 돌아갑니다. |
| Home | 첫 항목으로 이동합니다. |
| End | 마지막 항목으로 이동합니다. |
| 글자 키 | (선택 사항) 그 글자로 시작하는 다음 항목으로 이동합니다. |
| Esc | 메뉴를 닫고 메뉴를 연 요소로 포커스를 돌려보냅니다. |
| Tab | 모든 메뉴를 닫고 다음 포커스 요소로 이동합니다. |
사용 예
메뉴 버튼 + 메뉴
<button type="button" id="more" aria-haspopup="menu" aria-expanded="false" aria-controls="more-menu">더 보기</button>
<ul role="menu" id="more-menu" aria-labelledby="more" hidden>
<li role="menuitem" tabindex="-1">공유</li>
<li role="menuitem" tabindex="-1">신고</li>
<li role="separator"></li>
<li role="menuitem" tabindex="-1">삭제</li>
</ul>열고 닫기
function openMenu() {
menu.hidden = false;
btn.setAttribute('aria-expanded', 'true');
menu.querySelector('[role="menuitem"]').focus();
}
function closeMenu() {
menu.hidden = true;
btn.setAttribute('aria-expanded', 'false');
btn.focus();
}내비게이션 드롭다운을 menu로 만드는 실수
<button aria-haspopup="menu">고객센터</button>
<ul role="menu">
<li role="menuitem"><a href="/faq">자주 묻는 질문</a></li>
</ul>링크로 이동하는 하위 메뉴라면 <nav> 안에 aria-expanded 버튼과 일반 링크 목록을 둡니다(APG Disclosure Navigation).
직접 해 보기
“편집” 버튼으로 메뉴를 열고 ↑ ↓ Home End로 이동해 보세요. Enter로 실행하면 메뉴가 닫히고 포커스가 버튼으로 돌아옵니다. 버튼에서 ↑를 누르면 마지막 항목부터 열립니다.
실시간 코드 — 조작하면 속성 값이 바뀌는 모습을 볼 수 있습니다
화면낭독기에서는
| 상황 | 들리는 안내 (예) |
|---|---|
| 메뉴 버튼에 포커스 | 편집, 메뉴 버튼, 축소됨 |
| 메뉴를 엶 | 편집, 메뉴, 잘라내기, 메뉴 항목, 1/4 |
| Esc로 닫음 | 편집, 메뉴 버튼, 축소됨 |
사용 지침
이렇게 쓰세요
- 메뉴 항목·그룹·구분선만 자식으로 두고, 사이의
<li>래퍼에는role="none"을 줍니다. - 열 때 포커스를 메뉴 안으로, 닫을 때 연 요소로 옮깁니다.
- 메뉴를 여는 버튼에
aria-haspopup="menu"와aria-expanded를 씁니다.
이렇게 쓰지 마세요
- 사이트 내비게이션이나 값 선택 드롭다운에 쓰지 않습니다.
- 메뉴 안에 일반 링크·입력란을 섞지 않습니다.
- 메뉴가 열려 있을 때 Tab으로 항목 사이를 이동하게 하지 않습니다.
관련 역할·패턴
이 역할을 쓰는 패턴