Skip to content

Commit 2068c61

Browse files
committed
docs: 접근성 입문 가이드 및 UI 별 가이드 추가
1 parent abc1d8a commit 2068c61

39 files changed

+1669
-0
lines changed
124 KB
Binary file not shown.

fundamentals/a11y/basic-guide.md

Lines changed: 635 additions & 0 deletions
Large diffs are not rendered by default.

fundamentals/a11y/guide/tab.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# 탭(Tab)
2+
3+
탭은 관련된 콘텐츠를 그룹화하여 공간을 절약하고 사용자가 원하는 정보에 빠르게 접근할 수 있도록 하는 컴포넌트예요.
4+
5+
스크린리더와 키보드 사용자가 **탭 목록의 구조와 현재 활성 탭을 바로 이해하고 조작**하도록 구현하는 게 핵심이에요.
6+
7+
아래 내용은 특히 `aria-selected`, `role="tablist"``role="tab"` 의 차이 등 탭과 관련된 상태 속성을 다루는 법과 레이블 처리, 포커스 관리 등 실무에서 실수하기 쉬운 부분을 구체적으로 다뤄요.
8+
9+
---
10+
11+
<br />
12+
13+
## 이런 탭을 보여주려면 어떻게 구현해야 할까요?
14+
15+
![탭 예시](../images/tab.png)
16+
17+
18+
19+
```tsx
20+
<div>
21+
<button>홈</button>
22+
<button>관심</button>
23+
<button>발견</button>
24+
<button>피드</button>
25+
</div>
26+
```
27+
28+
겉보기에는 탭을 위한 기본적인 골격을 갖춘 것처럼 보이지만, 스크린리더는 이를 명확하지 않은 정보로 전달하게 돼요.
29+
30+
::: ❌ 접근성을 챙기지 않으면 이렇게만 들려요
31+
홈, 버튼
32+
관심, 버튼
33+
발견, 버튼
34+
피드, 버튼
35+
36+
:::
37+
38+
탭의 경우 각각의 개별적인 버튼들로 이루어진 것이 아닌, 현재 선택되어 있는지 여부를 공유하는 하나의 그룹이에요.
39+
40+
때문에 어떤 그룹인지, 그룹 안에서 어떤 것이 선택되어 있는지 사용자가 이해할 수 있어야 해요.
41+
42+
```tsx
43+
<div role="tablist" aria-label="메뉴">
44+
<button role="tab" aria-selected={false}>홈</button>
45+
<button role="tab" aria-selected={false}>관심</button>
46+
<button role="tab" aria-selected={false}>발견</button>
47+
<button role="tab" aria-selected={true}>피드</button>
48+
</div>
49+
```
50+
51+
::: ✅ 접근성을 챙기면 이렇게 들려요
52+
53+
메뉴, **탭 목록**
54+
홈, **선택됨**, ****
55+
관심, ****
56+
발견, ****
57+
피드, ****
58+
59+
:::
60+
61+
### 이런 것들을 챙겨야 해요
62+
63+
- 탭 목록은 `role="tablist"`로 감싸고, 각 탭은 `role="tab"`으로 구현해요.
64+
- 활성 탭에는 `aria-selected="true"``, 비활성 탭에는 `aria-selected="false"`를 설정해요.
65+
- 화면에 보이는 탭 텍스트가 의미를 충분히 담고 있다면 추가 `aria-label`은 생략해도 돼요.
66+
단, 아이콘만 있거나 텍스트가 모호하면 반드시 `aria-label`을 넣어요.
67+
68+
## role 속성으로 탭 컴포넌트 표현하기
69+
70+
탭을 구현할 때는 **탭 버튼 영역**(사용자가 선택하는 버튼들)과 **탭 콘텐츠 영역**(선택된 탭에 맞는 콘텐츠) 두 부분이 필요해요.
71+
72+
이 두 영역을 `tablist`, `tab`, `tabpanel` 역할로 명확히 구분해주면 스크린리더가 탭의 구조와 현재 선택 상태를 정확히 인식하고 전달할 수 있어요.
73+
74+
![탭 역할 예시](../images/tab-role-example.png)
75+
76+
각 역할이 담당하는 영역과 연결 방식, 그리고 역할을 올바르게 사용했을 때의 이점을 살펴볼게요.
77+
78+
### tablist와 tab
79+
```tsx
80+
<div role="tablist" aria-label="메뉴">
81+
<button role="tab">홈</button>
82+
<button role="tab">관심</button>
83+
<button role="tab">발견</button>
84+
<button role="tab">피드</button>
85+
</div>
86+
```
87+
88+
`role="tablist"`는 탭들의 컨테이너 역할로, 여러 탭이 하나의 그룹임을 나타내요. <br />
89+
`role="tab"`은 개별 탭 요소로, 각각의 탭이 어떤 콘텐츠를 담당하는지 명시하는 역할이에요.
90+
91+
92+
::: ✅ tablist로 tab을 묶어주면 이런 이점이 있어요
93+
94+
1. 상태 정보를 제공해요
95+
- tablist로 묶어주는 것 만으로 현재 선택된 탭과 선택되지 않은 탭을 구분해서 읽어줘요
96+
2. 키보드 네비게이션을 지원해요
97+
- 화살표 키로 탭 간 이동이 가능해요
98+
- Home/End 키로 첫 번째/마지막 탭으로 이동할 수 있어요
99+
3. 스크린리더로 효율적인 탐색이 가능해요
100+
- 탭 그룹 전체를 한 번에 건너뛸 수 있어요
101+
- 현재 활성화된 탭과 전체 탭 개수를 알려줘요
102+
103+
:::
104+
105+
### tabpanel
106+
107+
탭을 클릭하면 해당 탭과 관련된 콘텐츠가 보여야 해요. 이때 `role="tabpanel"``aria-labelledby`를 사용하면 어떤 탭과 연결되어 있는지 명확히 알 수 있어요.
108+
109+
```tsx
110+
<div role="tablist" aria-label="메뉴">
111+
<button role="tab" aria-selected={false} id="home-tab">홈</button>
112+
<button role="tab" aria-selected={false} id="interest-tab">관심</button>
113+
<button role="tab" aria-selected={false} id="discovery-tab">발견</button>
114+
<button role="tab" aria-selected={true} id="feed-tab" aria-controls="feed-panel">피드</button>
115+
</div>
116+
<ul role="tabpanel" id="feed-panel" aria-labelledby="feed-tab">
117+
<li>
118+
<h3>탭 컴포넌트에서 접근성을 지키며 구현하는 법</h3>
119+
<p>탭은 관련된 콘텐츠를 그룹화하여 공간을 절약하고 사용자가 원하는 정보에 빠르게 접근할 수 있도록 하는 컴포넌트예요.</p>
120+
</li>
121+
</ul>
122+
```
123+
124+
`role="tabpanel"`은 활성화된 탭의 콘텐츠가 담긴 영역이에요. tabpanel을 사용할 때는 `id`가 필수예요. 탭 버튼의 `aria-controls` 속성이 이 id를 참조해서 어떤 패널과 연결되어 있는지 알려주거든요.
125+
126+
또한 `aria-labelledby`를 추가할 수 있는데, 연결된 탭의 id를 참조해서 스크린리더가 "피드 탭의 패널"처럼 명확하게 읽어줄 수 있어요.
127+
128+
이때, 비활성화된 탭의 패널은 `hidden` 속성으로 숨겨야 해요.
129+
`aria-selected` 속성만으로는 스크린리더가 비활성 탭의 패널과 구분하지 못하기 때문이에요. `hidden` 속성을 사용하지 않으면 스크린리더가 모든 패널의 콘텐츠를 읽어버리게 돼요.
130+
131+
132+
::: ✅ tabpanel을 사용하면 이런 이점이 있어요
133+
134+
1. 탭과 콘텐츠의 연결관계가 명확해져요
135+
- 스크린리더가 "홈 탭의 패널"처럼 읽어줘요
136+
- 어떤 콘텐츠가 어떤 탭에 속하는지 바로 알 수 있어요
137+
2. 비활성 탭 콘텐츠를 숨길 수 있어요
138+
- `hidden` 속성으로 비활성 탭의 패널을 숨기면 불필요한 정보가 읽히지 않아요
139+
3. 키보드 네비게이션을 지원해요
140+
- 화살표 키로 탭 간 이동할 때 해당 탭의 콘텐츠를 자동으로 보여줘요
141+
142+
:::
43.6 KB
Loading
54.3 KB
Loading
387 KB
Loading
1.22 MB
Loading
190 KB
Loading
199 KB
Loading
170 KB
Loading

0 commit comments

Comments
 (0)