Cert
UNIT · 1.8

커스텀 위젯과 동적 콘텐츠

Custom Widgets and Dynamic Content

한국어 해설 KO

Original Text EN

APG 패턴(탭·아코디언·모달·콤보박스)의 접근성 구현과 동적 콘텐츠·무한 스크롤·토스트의 처리를 학습합니다.

Learn accessible implementation of APG patterns (tabs, accordions, modals, comboboxes) and handling of dynamic content, infinite scroll, and toasts.

학습 목표

탭·아코디언 패턴의 역할 구조와 키보드 동작을 설명할 수 있다

모달 다이얼로그의 필수 접근성 요건을 나열할 수 있다

콤보박스·자동완성의 ARIA 패턴을 이해한다

토스트·무한 스크롤 등 동적 콘텐츠의 접근성 처리를 설명할 수 있다

Learning Objectives

Explain the role structure and keyboard behavior of tab and accordion patterns

List the essential accessibility requirements of modal dialogs

Understand the ARIA pattern for comboboxes and autocomplete

Describe accessible handling of dynamic content like toasts and infinite scroll

탭과 아코디언

Tabs and Accordions

탭 패턴(APG): 컨테이너는 role="tablist", 각 탭은 role="tab", 패널은 role="tabpanel"입니다. 활성 탭은 aria-selected="true", 탭과 패널은 aria-controls/aria-labelledby로 상호 연결합니다. 키보드: 화살표 키로 탭 간 이동, Tab 키는 탭 목록을 벗어나 활성 패널로 이동합니다(로빙 tabindex — 활성 탭만 tabindex="0", 나머지는 "-1").

The tabs pattern (APG): the container is role="tablist", each tab role="tab", each panel role="tabpanel". The active tab carries aria-selected="true", and tabs and panels are cross-linked with aria-controls/aria-labelledby. Keyboard: arrow keys move between tabs; Tab leaves the tablist into the active panel (roving tabindex — only the active tab has tabindex="0", the rest "-1").

아코디언은 더 단순합니다: 각 헤더는 실제 `<button>`으로 만들고 aria-expanded로 열림 상태를, aria-controls로 패널을 연결합니다. 버튼을 제목 요소로 감싸면(`<h3><button>`) 제목 탐색과 위젯 동작을 모두 얻습니다. 두 패턴 모두 상태 변경 시 ARIA 값을 실제로 갱신하는 것이 핵심입니다.

Accordions are simpler: each header is a real `<button>` with aria-expanded for state and aria-controls for its panel. Wrapping the button in a heading (`<h3><button>`) gives both heading navigation and widget behavior. In both patterns, the crux is actually updating ARIA values when state changes.

APG 탭 패턴 골격 — role·aria-selected·roving tabindex
<div role="tablist" aria-label="설정">
  <button role="tab" id="t1" aria-selected="true" aria-controls="p1">일반</button>
  <button role="tab" id="t2" aria-selected="false" aria-controls="p2"
          tabindex="-1">알림</button>
</div>
<div role="tabpanel" id="p1" aria-labelledby="t1"></div>
<div role="tabpanel" id="p2" aria-labelledby="t2" hidden></div>
<!-- 화살표 키로 탭 간 이동, 활성 탭만 tabindex=0 (roving) -->

모달 다이얼로그

Modal Dialogs

모달의 필수 요건: role="dialog"와 aria-modal="true", 제목과의 aria-labelledby 연결, 열릴 때 포커스가 모달 안으로 이동, 포커스가 모달 내부에 갇힘(트랩), Esc로 닫기, 닫힐 때 트리거 요소로 포커스 복귀, 배경 콘텐츠의 inert 처리.

Modal essentials: role="dialog" with aria-modal="true", an aria-labelledby link to its title, focus moved inside on open, focus contained (trapped) within, Esc to close, focus returned to the trigger on close, and the background made inert.

네이티브 `<dialog>` 요소의 showModal()은 포커스 트랩·Esc·배경 inert를 상당 부분 기본 제공하므로 우선 검토할 가치가 있습니다. 커스텀 구현이라면 배경을 aria-hidden 처리하는 것만으로는 부족합니다 — 포커스가 여전히 배경으로 나갈 수 있어 실제 트랩 로직이 필요합니다.

The native `<dialog>` element's showModal() provides much of this — focus trapping, Esc, background inertness — and deserves first consideration. In custom implementations, aria-hidden on the background is not enough: focus can still escape into it, so real trap logic is required.

네이티브 dialog — 이름 연결과 초기 포커스
<dialog aria-labelledby="dlg-title">
  <h2 id="dlg-title">변경 사항 저장</h2>
  <p>저장하지 않은 변경 사항이 있습니다.</p>
  <button autofocus>저장</button>
  <button>취소</button>
</dialog>
<!-- showModal()은 포커스 트랩·ESC 닫기·inert 배경을 기본 제공 -->

콤보박스와 자동완성

Comboboxes and Autocomplete

콤보박스(검색 자동완성 포함)는 가장 구현 난도가 높은 패턴 중 하나입니다. 입력에 role="combobox", aria-expanded, 목록과의 aria-controls 연결, 목록은 role="listbox"와 role="option"들, 하이라이트된 옵션은 aria-activedescendant로 알립니다 — 포커스는 입력에 두고 활성 옵션만 갱신하는 방식입니다.

The combobox (including search autocomplete) is among the hardest patterns to implement. The input takes role="combobox" with aria-expanded and aria-controls pointing to the list; the list is role="listbox" containing role="option" items; the highlighted option is conveyed via aria-activedescendant — focus stays on the input while the active option updates.

결과 수 변화는 라이브 영역으로 알리고('검색 결과 12건'), 화살표 키로 옵션 탐색, Enter로 선택, Esc로 목록 닫기를 구현합니다. 가능하다면 `<select>`나 `<datalist>` 같은 네이티브 요소로 요구를 충족할 수 있는지 먼저 검토하세요 — 첫 번째 ARIA 규칙은 여기서도 유효합니다.

Announce result-count changes via a live region ('12 results'), and implement arrow-key navigation, Enter to select, Esc to close. Where possible, first check whether native `<select>` or `<datalist>` meets the need — the First Rule of ARIA applies here too.

토스트, 무한 스크롤, 스켈레톤

Toasts, Infinite Scroll, Skeletons

토스트 알림은 role="status"(중요 오류는 role="alert") 컨테이너를 페이지 로드 시부터 두고 내용만 갱신해야 안정적으로 낭독됩니다. 자동 소멸 시간은 충분히 길거나 정지 가능해야 하며(WCAG 2.2.1), 토스트 안에 버튼이 있다면 사라지기 전에 도달할 수 있어야 합니다.

Toast notifications announce reliably when a role="status" container (role="alert" for critical errors) exists from page load and only its content updates. Auto-dismiss must be long enough or pausable (WCAG 2.2.1), and any button inside a toast must be reachable before it disappears.

무한 스크롤은 키보드 사용자가 푸터에 도달할 수 없게 만들 수 있습니다 — '더 보기' 버튼 방식이 접근성 면에서 우월합니다. 콘텐츠 추가 시 새 항목 수를 라이브 영역으로 알리고, 로딩 스켈레톤에는 aria-hidden을 주되 로딩 상태 자체는 aria-busy나 상태 텍스트로 전달합니다.

Infinite scroll can make the footer unreachable for keyboard users — a 'Load more' button is superior for accessibility. Announce the number of newly added items via a live region, give loading skeletons aria-hidden, and convey the loading state itself with aria-busy or status text.

단원 퀴즈

6문제 · 오답은 오답노트에 자동 저장됩니다

1

APG 탭 패턴에서 탭 간 이동에 사용하는 키는?

2

모달 구현에서 배경을 aria-hidden 처리하는 것만으로 부족한 이유는?

3

콤보박스에서 포커스를 입력에 둔 채 하이라이트된 옵션을 알리는 속성은?

4

무한 스크롤 대신 '더 보기' 버튼이 접근성 면에서 우월한 이유는?

5

토스트 알림이 안정적으로 낭독되게 하는 구현 방법은?

6

커스텀 드롭다운을 열어도 스크린 리더가 아무것도 읽지 않습니다. 진단을 시작할 가장 효율적인 지점은?

로드맵으로
로그인하면 학습 메모를 작성할 수 있습니다.

댓글

댓글을 불러오는 중...

댓글을 작성하려면 로그인이 필요합니다.