본문으로 건너뛰기
Dot Design System
v0.3.1

Accessibility

키보드, 화면 읽기, 확대와 모션 감소를 기본 계약으로 다룹니다.

목적

접근성은 별도 사용자군을 위한 추가 기능이 아니라 Dot의 목적을 누구나 같은 수준으로 완료하게 하는 제품 품질이다. 사용자는 pointer, keyboard, screen reader, 확대, 고대비, reduced motion 등 다양한 방식으로 사람·데이터·배움의 관계를 이해하고 다음 행동으로 이동할 수 있어야 한다.

  • Flexible: 입력 방식과 인지·감각 조건에 맞게 표현을 바꾸되 기능과 정보는 유지한다.
  • Link: label과 control, 상태와 대상, 오류와 복구, 현재와 다음 위치의 programmatic 관계를 보존한다.
  • Glow: 시각 강조 없이도 같은 방향과 상태를 이해할 수 있어야 한다.

기본 계약

  • 모든 interactive element는 keyboard로 도달하고 실행할 수 있다.
  • focus-visible indicator를 제거하지 않는다.
  • interactive target은 최소 40×40px이다.
  • 정보 텍스트는 12px 이상이다.
  • 상태와 선택을 color만으로 전달하지 않는다.
  • icon-only action은 accessible name을 가진다.
  • form control은 programmatic label을 가진다.
  • motion 감소 설정을 존중한다.
  • hover 없이도 필수 정보와 action을 사용할 수 있다.
  • loading, error, result는 필요한 관계와 announcement를 제공한다.

Semantic structure

  • 페이지에는 하나의 h1이 있다.
  • heading은 h1 → h2 → h3 순서를 지키고 시각 size만으로 구조를 만들지 않는다.
  • main, navigation, complementary 등 landmark가 중복되면 고유한 accessible name을 제공한다.
  • list는 실제 list semantics, table은 실제 행·열 비교가 있을 때 table semantics를 사용한다.
  • div에 click handler를 붙여 Button이나 link를 흉내 내지 않는다.
  • route와 앱 shell이 이미 소유한 main과 page의 PageScaffold 관계를 검토해 landmark를 중복하지 않는다.

Keyboard

  • Tab 순서는 시각적·논리적 순서와 일치한다.
  • Button은 Enter와 Space, link는 Enter라는 기본 동작을 유지한다.
  • custom keyboard interaction은 익숙한 pattern과 public primitive behavior를 따른다.
  • Sidebar shortcut은 제품이 명시적으로 설정한 경우에만 활성화하고 input, textarea, content-editable에서 가로채지 않는다.
  • Escape는 Dialog, Sheet, Popover처럼 현재 overlay를 닫되 입력 내용을 조용히 폐기하지 않는다.
  • arrow key navigation이 있는 composite control은 Tab과의 역할을 명확히 한다.
  • drag-and-drop, hover menu, pointer gesture에는 keyboard 대안을 제공한다.

Focus

  • focus ring은 모든 배경에서 식별 가능하고 component에 잘리지 않는다.
  • Dialog와 Sheet가 열리면 focus를 의미 있는 내부 위치로 이동하고 닫으면 trigger로 돌려보낸다.
  • 위험 확인 dialog는 destructive action에 자동 focus하지 않는다.
  • route 변경 뒤에는 페이지 h1 또는 새 작업의 시작점으로 focus를 이동할 수 있어야 한다.
  • 삭제된 item에 focus가 있었다면 결과 메시지 또는 다음 유효 item으로 이동한다.
  • validation 제출 후 첫 오류로 focus를 이동할 수 있지만 사용자가 읽던 맥락을 설명한다.
  • background refresh와 streaming update는 사용자의 focus를 빼앗지 않는다.

Forms

FormField는 id, label, description, error 관계를 연결하는 기본 composition이다.

  • label은 항상 control과 programmatically 연결한다.
  • placeholder를 label로 사용하지 않는다.
  • required 여부는 symbol만이 아니라 accessible state로 전달한다.
  • description은 입력 전에 필요한 판단 기준을 제공한다.
  • error는 무엇이 잘못됐고 어떻게 복구하는지 설명한다.
  • error와 description은 control의 accessible description 관계에 포함한다.
  • disabled와 read-only를 구분하고 이유를 인접하게 제공한다.
  • 단위, 형식, 허용 범위는 입력 전에 알 수 있게 한다.
  • 자동 완성, paste, password manager 같은 사용자 도구를 불필요하게 막지 않는다.

Status와 feedback

  • success, warning, destructive, info는 text label을 가진다.
  • StatusPill의 tone과 dot은 보조 신호이며 children text가 실제 상태를 설명한다.
  • loading container에는 필요한 경우 aria-busy를 사용한다.
  • 짧은 비차단 결과는 적절한 live region으로 알린다.
  • toast가 사라져도 중요한 상태와 action은 page에 남는다.
  • error summary가 있으면 각 field error로 이동할 수 있게 한다.
  • 일부 성공은 성공·실패 범위가 screen reader에도 같은 순서로 전달된다.
  • background update는 반복 announcement로 작업을 방해하지 않는다.

Overlay

  • Dialog와 AlertDialog는 제목과 설명을 가진다.
  • 열릴 때 focus가 내부로 이동하고 배경 content는 interaction 대상에서 제외된다.
  • 닫으면 trigger로 focus를 돌려보낸다.
  • Popover와 DropdownMenu의 trigger는 expanded 상태와 관계를 제공한다.
  • Tooltip은 accessible name을 대신하지 않고 짧은 보충 설명만 제공한다.
  • overlay는 DotTheme 내부 portal root를 사용해 token, focus, reset scope를 유지한다.
  • modal 안에서 또 다른 modal을 열어 focus depth를 복잡하게 만들지 않는다.

Table, list, and dense UI

  • Table은 caption 또는 주변 heading으로 목적을 알 수 있다.
  • column header와 row header 관계를 유지한다.
  • sort 가능한 header는 현재 방향과 변경 방법을 전달한다.
  • clickable row와 내부 action target을 겹치지 않는다.
  • mobile record list로 전환할 때 label과 value 관계를 보존한다.
  • selection count와 전체 범위를 text로 제공한다.
  • virtualized list는 전체 count, 현재 위치, focus 보존, screen reader 탐색을 별도로 검증한다.
  • horizontal scroll 영역에는 accessible name과 keyboard scroll 경로가 있다.

Responsive, zoom, and reflow

  • 200% zoom에서 content와 action이 잘리거나 겹치지 않는다.
  • text 확대 시 고정 높이 container가 label, error, status를 자르지 않는다.
  • 좁은 화면에서 table을 단순히 숨기지 않고 모든 핵심 정보를 record list로 재구성한다.
  • mobile keyboard가 focused field와 error를 가리지 않는다.
  • fixed header, WorkflowBar, toast가 focus target을 가리지 않는다.
  • orientation과 viewport가 바뀌어도 selection, input, focus를 보존한다.
  • horizontal과 vertical scroll을 동시에 강요하는 영역을 줄인다.

Color and contrast

  • ink-strong, ink-default, ink-subtle은 실제 surface 조합에서 대비를 검증한다.
  • ink-disabled는 정보가 실제로 unavailable할 때만 사용한다.
  • selected, focus, error, success를 color 하나로 구분하지 않는다.
  • chart는 legend, direct label, pattern 등 color 외 식별 방법을 제공한다.
  • gradient text는 핵심 정보와 긴 본문에 사용하지 않는다.
  • forced colors와 고대비 환경에서 border, focus, control이 유지되는지 확인한다.

Motion and media

  • .dot-theme의 reduced-motion fallback을 우회하지 않는다.
  • animation이 없어도 상태 변화와 공간 관계를 text와 structure로 이해할 수 있다.
  • DotMotion에는 실제 작업을 설명하는 ariaLabel과 시각 text를 제공한다.
  • 반복 motion은 실제 처리·발화가 끝나면 중단한다.
  • flash, rapid blink, 반복 shake를 사용하지 않는다.
  • 자동 재생되는 장시간 media가 있다면 pause, stop, hide 정책을 제공한다.

Character와 brand asset

  • character가 장식이면 빈 alt를 사용하고 보조 기술에서 중복되지 않게 한다.
  • character가 실제 의미를 가지면 주변 text와 겹치지 않는 설명을 제공한다.
  • 캐릭터 없이도 목적, 상태, action을 이해할 수 있어야 한다.
  • 2D는 제품·답변·처리 맥락, 3D는 넓고 드문 브랜드 맥락이라는 사용 범위를 유지한다.
  • DotCharacter의 최소 100px과 지정된 형태, 색, 관계, clear space를 지킨다.
  • Glow와 gradient가 제거돼도 같은 정보 위계와 다음 방향을 제공한다.

AI experience

  • 생성 중, 생성 완료, 검토 중, 확정, 적용 상태를 text로 구분한다.
  • streaming content를 매 token마다 announcement하지 않고 의미 있는 단위로 알린다.
  • keyboard로 결과를 탐색, 수정, 제외, 확정할 수 있다.
  • 다시 생성할 때 사용자 수정이 사라지면 실행 전에 알린다.
  • AI 결과의 한계와 검토 필요 상태를 시각 효과에만 맡기지 않는다.
  • 긴 결과가 새로 추가될 때 focus와 scroll을 강제로 이동하지 않는다.
  • 사람이 검토해야 하는 결과에 건너뛸 수 없는 시각 전용 interaction을 만들지 않는다.

Content

  • accessible name은 시각 label과 같은 결과를 말한다.
  • 여기를 클릭, 더보기보다 목적지와 내용을 구체적으로 쓴다.
  • 오류는 실패한 일, 영향, 복구 행동을 포함한다.
  • 기술 식별자는 필요한 경우에만 보조 정보로 제공한다.
  • 상태 변화는 너무 자주 반복하지 않고 중요한 변화만 알린다.
  • 학습 완료와 다음 배움의 방향을 text로 연결한다.

예외와 피해야 할 사용

  • 접근성 문제를 Tooltip이나 sr-only text 추가만으로 해결하지 않는다.
  • focus outline을 제거하고 box-shadow만 약하게 남기지 않는다.
  • click 가능한 div와 span을 만들지 않는다.
  • placeholder, icon, color를 label 대체로 사용하지 않는다.
  • disabled Button만 보여주고 이유를 알 방법을 없애지 않는다.
  • mobile에서 핵심 정보를 숨기지 않는다.
  • live region에 화면 전체 content를 반복해서 넣지 않는다.
  • character와 animation으로 상태 text를 대체하지 않는다.
  • public primitive의 keyboard behavior를 custom handler로 깨뜨리지 않는다.

검증 방법

최소 다음 방식으로 확인한다.

  1. mouse 없이 전체 핵심 흐름을 완료한다.
  2. focus indicator와 순서를 확인한다.
  3. screen reader로 heading, landmark, form, status, overlay 흐름을 확인한다.
  4. 200% zoom과 narrow viewport에서 reflow를 확인한다.
  5. reduced motion과 고대비 환경을 확인한다.
  6. loading, empty, error, partial success, disabled 상태를 각각 확인한다.
  7. 실제 긴 한국어, 큰 숫자, 오류 문구로 overflow를 확인한다.
  8. 자동 검사 결과를 수동 keyboard·screen reader 검토로 보완한다.

검토 질문

  • keyboard만으로 화면의 완료 기준에 도달할 수 있는가?
  • 모든 focus가 보이고 논리적 순서로 이동하는가?
  • heading과 landmark가 시각 구조와 일치하는가?
  • form label, help, error가 control과 연결되는가?
  • 상태, 선택, 위험을 color 없이 이해할 수 있는가?
  • overlay의 focus 이동과 trigger 복귀가 정확한가?
  • 40×40px target과 12px 이상 정보 text를 지키는가?
  • zoom, narrow, mobile keyboard에서도 핵심 content가 보이는가?
  • reduced motion에서도 같은 상태와 다음 방향을 이해할 수 있는가?
  • character와 Glow 없이도 한 학습 고리와 다음 배움을 완료할 수 있는가?