역할 · 위젯
role="treeitem"
트리(tree) 안의 항목입니다. 하위 항목이 있으면 펼치고 접을 수 있습니다.
한눈에 보기
- 분류
- 위젯
- 대응 HTML
- 없음
- 이름 정하는 방법
- 콘텐츠, 작성자
- 이름 필수
- 예
- 필수 하위 요소
- 없음
설명
treeitem은 tree의 항목입니다. 하위 항목이 있는 항목(부모 노드)은 aria-expanded로 펼침 상태를 알리고, 하위 항목들은 role="group"으로 감싸 부모 항목 안에 둡니다. 하위 항목이 없는 항목(끝 노드)에는 aria-expanded를 붙이지 않습니다.
- 위치 정보 — DOM이 중첩 구조(
tree›treeitem›group›treeitem)라면 브라우저가 수준·위치를 계산합니다. 평평한 DOM이나 일부만 불러오는 트리는aria-level,aria-posinset,aria-setsize를 직접 넣습니다. - 선택 — 선택 가능한 트리는
aria-selected를 씁니다. 여러 개를 고를 수 있으면 트리에aria-multiselectable="true"를 주고, 선택 가능한 모든 항목에true/false를 명시합니다. 체크박스형 선택이 필요하면aria-checked(혼합 상태 포함)를 쓸 수 있지만 한 트리에서 두 방식을 섞지 않습니다.
aria-selected의 필수 여부
WAI-ARIA 1.2 표에서는 treeitem이 option을 상속하면서 aria-selected가 “필수”로 함께 상속된 것처럼 표시됩니다. 그러나 APG 트리 뷰 패턴은 선택 기능이 없는 트리나 단일 선택 트리에서 선택되지 않은 항목에 aria-selected를 생략하는 방식을 허용합니다. 선택 기능이 있다면 상태를 명시하는 것이 가장 안전합니다.
항목의 이름은 콘텐츠에서 계산되며, 중첩된 하위 그룹의 텍스트는 보통 부모 항목 이름에 포함되지 않도록 브라우저가 처리합니다. 그래도 이름이 길게 읽히면 라벨 부분을 별도 요소로 두고 aria-labelledby로 지정할 수 있습니다.
테스터 관점
- 항목마다 “펼쳐짐/접힘”, 수준(레벨), “n개 중 m번째”가 읽히는지 확인합니다.
- 접힌 항목의 하위 항목이 가상 커서로도 읽히지 않는지(숨김 처리) 확인합니다.
- →/←가 펼치기·접기·부모 이동을 APG 규칙대로 하는지 확인합니다.
함께 쓰는 속성
지원 속성
전역 속성(이름·설명 등)은 모든 역할에 쓸 수 있어 생략했습니다.
키보드 동작
| 키 | 동작 |
|---|---|
| ↓ | 펼치거나 접지 않고, 화면에 보이는 다음 항목으로 이동합니다. |
| ↑ | 화면에 보이는 이전 항목으로 이동합니다. |
| → | 접힌 부모 항목: 펼칩니다(포커스는 그대로). 펼쳐진 부모 항목: 첫 하위 항목으로 이동합니다. 끝 항목: 아무 일도 하지 않습니다. |
| ← | 펼쳐진 부모 항목: 접습니다. 하위 항목: 부모 항목으로 이동합니다. 접힌 최상위 항목: 아무 일도 하지 않습니다. |
| Home | 첫 항목으로 이동합니다. |
| End | 화면에 보이는 마지막 항목으로 이동합니다. |
| Enter | 항목을 실행(기본 동작)합니다. 예: 파일 열기, 선택. |
| 글자 키 | (권장) 그 글자로 시작하는 다음 항목으로 이동합니다. |
| * | (선택 사항) 현재 항목과 같은 수준의 형제 항목을 모두 펼칩니다. |
| Space | (다중 선택) 포커스된 항목의 선택을 바꿉니다. |
| Shift + ↓ | (다중 선택, 선택 사항) 다음 항목으로 이동하며 선택을 바꿉니다. Shift+↑는 반대 방향입니다. |
| Ctrl + A | (다중 선택, 선택 사항) 모든 항목을 선택합니다. |
사용 예
중첩 구조
<ul role="tree" aria-label="파일">
<li role="treeitem" aria-expanded="true" aria-selected="false">
<span>src</span>
<ul role="group">
<li role="treeitem" aria-selected="false">index.html</li>
<li role="treeitem" aria-selected="false">app.js</li>
</ul>
</li>
<li role="treeitem" aria-selected="false">README.md</li>
</ul>평평한 DOM에서 위치 정보 직접 지정
<div role="tree" aria-label="조직도">
<div role="treeitem" aria-level="1" aria-posinset="1" aria-setsize="1" aria-expanded="true">대표</div>
<div role="treeitem" aria-level="2" aria-posinset="1" aria-setsize="2">개발팀</div>
<div role="treeitem" aria-level="2" aria-posinset="2" aria-setsize="2">디자인팀</div>
</div>펼치기·접기
function setExpanded(item, open) {
if (!item.hasAttribute('aria-expanded')) return; // 끝 항목
item.setAttribute('aria-expanded', String(open));
item.querySelector('[role="group"]').hidden = !open;
}끝 항목에 aria-expanded를 붙이는 실수
<li role="treeitem" aria-expanded="false">README.md</li>
<!-- 펼칠 것이 없는데 “접힘”으로 읽혀 사용자가 계속 펼치려 합니다 -->직접 해 보기
트리에 포커스를 두고 ↑ ↓로 이동, →로 펼치거나 첫 하위 항목으로, ←로 접거나 상위 항목으로 이동해 보세요. Enter는 항목을 선택하고, *는 같은 수준의 항목을 모두 펼칩니다. 글자 키를 누르면 그 글자로 시작하는 다음 항목으로 이동합니다.
- src
- components
- button.js
- dialog.js
- index.html
- style.css
- components
- docs
- guide.md
- README.md
실시간 코드 — 조작하면 속성 값이 바뀌는 모습을 볼 수 있습니다
화면낭독기에서는
| 상황 | 들리는 안내 (예) |
|---|---|
| 트리로 처음 이동 | 프로젝트 파일, 트리 뷰, src, 확장됨, 1/3, 수준 1 |
| ↓로 하위 항목 | components, 축소됨, 1/3, 수준 2 |
| →로 펼침 | 확장됨 |
사용 지침
이렇게 쓰세요
tree안에 직접 넣거나, 부모 항목 안의group에 넣습니다.- 부모 항목에만
aria-expanded를 붙이고, 접히면 하위 그룹을 숨깁니다. - 로빙 tabindex로 트리 전체가 탭 정지 하나가 되게 합니다.
이렇게 쓰지 마세요
- 끝 항목에
aria-expanded를 붙이지 않습니다. - 사이트 내비게이션 링크 목록을 트리로 만들지 않습니다. 대부분 디스클로저 내비게이션이 더 알맞습니다.
- 한 트리에서
aria-selected와aria-checked를 섞어 쓰지 않습니다.