reopt designreopt design
DocsExploreToolsPricingBuilder
시작하기
개요
시작하기
Next.js 설치
Private install
핵심 개념
아키텍처
컴포지션 패턴
접근성
키보드 패턴
스타일링
테마 시스템
고급 패턴
구축·운영
Skills
AI 연동
CLI (opt surface add)
의존 그래프
도구
Canvas 카탈로그
Theme Builder
Form Builder
템플릿
템플릿
릴리즈
릴리즈 노트
Oopt-ui
reopt designreopt design

AI 시대를 위한 디자인 시스템

  • 문서
  • 가격
  • 릴리즈 노트
  • GitHub
  • 서비스 약관
  • 개인정보처리방침

© 2026 reopt-ai. All rights reserved.

핵심 개념
  1. 문서
  2. /
  3. 핵심 개념
  4. /
  5. 접근성

접근성

Spatial Navigation, 포커스 관리, WAI-ARIA 역할, 키보드 단축키를 설명합니다.

reopt design · 업데이트 2026년 6월 26일

Primitive 기반 접근성

opt-ui의 모든 Primitive는 @reopt-ai/opt-ui-primitives 기반으로 구현됩니다. 이 레이어는 WAI-ARIA 역할과 상태, roving tabindex 패턴, 포커스 트랩 같은 접근성 동작을 제공합니다.

개발자는 접근성 세부사항을 직접 구현할 필요 없이 Primitive를 조합하면 됩니다. 역할, 상태, 키보드 인터랙션은 Primitive 계층이 담당합니다.

Spatial Navigation

방향키(↑↓←→)로 화면의 포커스 가능한 요소 사이를 공간적으로 이동하는 시스템입니다. 7단계 판정 흐름으로 동작합니다:

단계판정
1. 방향키 확인Arrow 키가 아니면 무시
2. defaultPreventedComposite/Menu/Listbox 등이 이미 처리했으면 건너뜀
3. 수식키Ctrl/Meta/Alt/Shift 동반 시 무시
4. activeElement포커스된 요소 없으면 무시
5. 입력 보호입력 필드 내 방향키는 해당 필드에 양보
6. 트랩 컨텍스트dialog/menu/listbox 내부에서는 비활성화
7. 후보 계산방향 기준 가장 가까운 요소로 포커스 이동
tsx
// spatial-nav.ts — 핵심 판정 흐름

function handleKeyDown(e: KeyboardEvent): void {
  // 1. 방향키 확인
  if (!ARROW_KEYS.has(e.key)) return;
  const dir = getDirection(e.key);

  // 2. 이미 처리됨 (Composite/Listbox/Menu 등)
  if (e.defaultPrevented) return;

  // 3. 수식키 동반
  if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return;

  // 4. activeElement 확인
  const el = document.activeElement as HTMLElement;
  if (!el || el === document.body) return;

  // 5. 입력 필드 보호
  if (shouldSkipArrow(el, dir)) return;

  // 6. dialog/menu/listbox 내부
  if (isInsideTrappedContext(el)) return;

  // 7. 후보 계산 및 포커스 이동
  const target = findBestCandidate(el, getTabbableElements(), dir);
  if (target) {
    e.preventDefault();
    target.focus({ preventScroll: false });
  }
}

입력 필드 보호

입력 필드 유형별로 방향키 동작이 다르게 보호됩니다:

입력 유형보호 방향이유
text, email, url, tel, password← →커서 이동
number↑ ↓값 증감
range← →값 조절
textarea전체커서 이동 (2D)
select전체옵션 탐색

트랩 컨텍스트

dialog, menu, listbox, tree 등 내부에서는 Spatial Navigation이 비활성화됩니다. 이들 컨텍스트는 자체 키보드 탐색을 제공하므로, 충돌을 방지합니다.

tsx
export function getTrappedContextRole(el: HTMLElement): string | null {
  let node: HTMLElement | null = el;
  while (node) {
    const role = node.getAttribute("role");
    if (
      role === "dialog" || role === "alertdialog" ||
      role === "menu" || role === "listbox" || role === "tree"
    ) {
      return role;
    }
    if (node.hasAttribute("data-dialog")) return "dialog";
    if (node.hasAttribute("data-popover")) return "popover";
    node = node.parentElement;
  }
  return null;
}

RouteFocusManager

페이지 전환(Next.js 라우팅) 시 RouteFocusManager가 자동으로 h1 요소에 포커스를 이동합니다. 이를 통해 스크린 리더 사용자가 새 페이지의 제목을 즉시 인지할 수 있습니다.

WAI-ARIA 역할 맵

컴포넌트ARIA role키보드 조작
Tabstablist, tab, tabpanel←→ 탭 전환, Home/End
DialogdialogEsc 닫기, 포커스 트랩
Menumenubar, menu, menuitem←→ 메뉴 전환, ↑↓ 아이템 탐색
Selectlistbox, option↑↓ 옵션 탐색, Enter 선택
Comboboxcombobox, listbox↑↓ 후보 탐색, Enter 선택
Toolbartoolbar←→ 아이템 탐색
Disclosurebutton (trigger)Enter/Space 토글
CompositeZonegrid, row, gridcell↑↓←→ 2D 탐색

키보드 단축키

단축키동작
Cmd+K커맨드 팔레트 열기
Ctrl+Shift+FUI 디버거 토글
↑ ↓ ← →Spatial Navigation (포커스 이동)
Tab다음 포커스 가능 요소로 이동
Enter / Space버튼 활성화, Disclosure 토글
Esc다이얼로그/메뉴/팝오버 닫기

정적 분석 (ESLint)

opt-ui는 ESLint 규칙으로 접근성과 컴포넌트 품질을 빌드 시점에 강제합니다. @reopt/eslint-config에 정의된 규칙은 세 범주로 나뉩니다.

접근성 (jsx-a11y)

규칙심각도효과
alt-texterror이미지 alt 텍스트 누락 방지
aria-propserror잘못된 aria-* 속성 감지
aria-proptypeserror잘못된 aria-* 값 감지
aria-roleerror잘못된/추상 ARIA role 방지
role-has-required-aria-propserrorrole별 필수 aria prop 누락
heading-has-contenterror빈 heading 방지
interactive-supports-focuserror인터랙티브 요소 포커스 필수
tabindex-no-positiveerror양수 tabIndex 금지
click-events-have-key-eventswarnonClick에 키보드 핸들러 동반
no-static-element-interactionswarndiv/span에 핸들러 시 role 필요
anchor-has-contentwarn빈 앵커 태그 방지
label-has-associated-controlwarnlabel-input 연결 강제

React 컴포넌트 품질

규칙심각도효과
button-has-typeerrorbutton type 속성 필수
jsx-keyerror배열 렌더링 시 key 누락
jsx-no-target-blankerrortarget="_blank" 보안
jsx-pascal-caseerror컴포넌트명 PascalCase
void-dom-elements-no-childrenerrorvoid 요소에 children 금지
self-closing-compwarn빈 컴포넌트 자기 닫기 (auto-fix)
jsx-curly-brace-presencewarn불필요한 중괄호 제거 (auto-fix)
jsx-fragmentswarnFragment 단축 문법 사용 (auto-fix)

테스트 품질 (testing-library)

테스트 파일(**/__tests__/**, *.test.*)에만 적용됩니다.

규칙심각도효과
prefer-screen-querieswarnscreen.getBy* 사용 권장
no-wait-for-multiple-assertionswarnwaitFor 내 단일 assertion
prefer-user-eventwarnfireEvent 대신 userEvent 권장
no-containerwarncontainer 직접 접근 지양

커스텀 규칙

no-restricted-imports로 @reopt-ai/opt-ui-primitives 직접 import를 금지합니다. 모든 프리미티브는 반드시 @reopt-ai/opt-ui를 통해 사용해야 합니다.

개발 도구

opt-ui는 접근성 개발을 위한 두 가지 도구를 제공합니다:

opt-devtool

개발 모드 전용 전역 inspect overlay. Ctrl+Shift+F로 토글하여 포커스 흐름, Tab 순서, 컴포넌트 계층과 module snapshot을 함께 시각화합니다.

DesignGuidePanel

디자인 시스템 참조 패널. Primitive 맵, 키보드 패턴, Tailwind 셀렉터, 접근성 속성 등 6개 섹션을 제공합니다.

Previous컴포지션 패턴Shell이 Core를 조합하는 방식, 데이터 주도 렌더링, 커스텀 Shell 가이드핵심 개념
컴포지션 패턴 페이지로 이동
Next키보드 패턴CompositeZone, roving tabindex, 방향키 탐색, Esc/Enter 패턴을 예제로 정리핵심 개념