Astro UI 패턴 및 이식 가능한 컴포넌트 라이브러리
이 가이드는 Astro 사이트를 위한 이식 가능한 드롭인 UI 컴포넌트의 표준화된 카탈로그를 정의합니다.
독립 실행형 예제는 이식 가능한 컴포넌트 모델을 사용합니다: npm 종속성 제로, 클라이언트 프레임워크 런타임 제로(React/Vue 없음), 네임스페이스가 적용되고 내장된 폴백이 있는 CSS 토큰, 점진적 향상. 프레임워크 프로젝트에서는 의미론적 및 인터랙션 요구사항을 유지하면서 선택된 계약에 맞게 구성과 스타일을 조정합니다. 렌더링된 프로젝트에서 접근성을 확인하세요. 템플릿만으로는 WCAG 적합성을 보장하지 않습니다.
동작 계약 및 프레임워크 구성
아래 색인의 컴포넌트에 대해 의미론적 및 인터랙션 계약을 사용하세요: 키보드 지원, 포커스 관리, 네이티브 요소, 접근 가능한 이름, 상태 업데이트 및 점진적 향상. 선택된 프로젝트/프레임워크 계약이 스타일링, 토큰, 가져오기 및 컴포넌트 구성을 제어합니다. 사용자 지침이 우선합니다.
예제는 아래의 독립 실행형 이식 가능한 컴포넌트 모델을 사용합니다. 프레임워크 구성 계약 없이 독립적인 컴포넌트를 추가할 때 사용하세요. 프로젝트에 기존 라이브러리가 있는 경우, 중복 버튼, 제목 또는 폼 컨트롤을 만드는 대신 적절한 기본 요소를 사용하여 동작을 조정하세요. 예제의 래퍼와 클래스를 조정하면서 필요한 의미론과 동작을 유지하세요.
컴포넌트 프레임워크(Lumos 등)를 기반으로 구축된 프로젝트의 경우 해당 프레임워크의 구성 및 스타일링을 사용하세요. 해당 기본 요소를 가져올 수 있습니다. 독립 실행형 제로 사이트 임포트 규칙과 네임스페이스가 적용된 폴백 토큰은 선택된 프레임워크의 자체 계약을 재정의하지 않습니다.
이식 가능한 컴포넌트 모델
독립 실행형 이식 가능한 컴포넌트의 경우 다음 다섯 가지 규칙을 사용하세요. 선택된 프레임워크에서는 위에서 설명한 대로 동작 요구사항을 유지하고 구성/스타일링 계약을 따르세요:
- 외부/사이트 임포트 제로: 컴포넌트 파일은 사이트 레이아웃, 버튼 또는 타사 클라이언트 UI 라이브러리를 가져오면 안 됩니다. 유일한 예외는 SelfHostedMap으로, 맵 렌더러와 타일 리더가 필요합니다. 사양에 패키지가 나열되어 있으며 소유자의 승인을 받아야만 설치됩니다.
- 폴백이 있는 네임스페이스 CSS 변수: 컴포넌트 스타일시트 내에서 호스트 토큰(예:
var(--color-brand))을 직접 참조하지 마세요. 항상var(--comp-property, <fallback>)형식을 사용하세요. - 범위 지정 BEM 및 CSS 논리 속성: BEM 클래스 이름 지정(
.c-theme-toggle,.c-accordion__summary) 및 논리 속성(inline-size,block-size,padding-inline,margin-block)을 사용하세요. - 멱등적인 바닐라 점진적 향상: 스크립트는 로드 시 실행되어야 하며 Astro View Transitions가 활성화된 경우 깔끔하게 다시 연결되어야 합니다(
document.addEventListener('astro:after-swap', init)). - 터치 대상 및 ARIA: 버튼과 인터랙티브 컨트롤은 최소
44px(2.75rem) 또는48px(3rem) 터치 대상, 적절한 ARIA 상태(aria-expanded,aria-selected,aria-pressed,aria-controls) 및 키보드 포커스 링을 가져야 합니다.
컴포넌트 색인
| 컴포넌트 | 사양 파일 | 목적 | 주요 계약 |
|---|---|---|---|
| 1. ThemeToggle | components/theme-toggle.md | FOUC 없이 SVG 모핑을 사용한 라이트/다크 테마 전환기 | <head> 인라인 스크립트 + OKLCH 토큰 매핑 |
| 2. MobileNavDrawer | components/mobile-nav-drawer.md | 애니메이션 햄버거 메뉴가 있는 접근 가능한 슬라이드다운 네비게이션 드로어 | 48px 터치 대상, Escape 키 닫기, GPU 블러 지연 없음 |
| 3. SearchBar | components/search-bar.md | 지우기 버튼과 라이브 알리미가 있는 클라이언트 측 검색 입력 | rAF 디바운싱(최적의 INP), aria-live, 사용자 정의 이벤트 코디네이터 |
| 4. FilterChips | components/filter-chips.md | 접근 가능한 눌린 상태가 있는 다중 카테고리 필 칩 필터 바 | role="group", aria-pressed, 사용자 정의 이벤트 코디네이터 |
| 5. SearchFilterBar | components/search-filter-bar.md | SearchBar와 FilterChips를 결합한 복합 패턴 | 사전 구성된 스택형 도구 모음, 다중 열 플렉스 레이아웃, 공유 범위 |
| 6. AccessibleModal | components/accessible-modal.md | 네이티브 HTML5 <dialog>를 사용한 접근 가능한 대화상자 오버레이 | 네이티브 최상위 레이어, 배경 클릭, Escape 키, 포커스 복원 |
| 7. AccessibleAccordion | components/accessible-accordion.md | 부드러운 CSS 그리드 확장을 사용한 네이티브 FAQ/아코디언 | 네이티브 <details name="...">, 0 KB JavaScript |
| 8. AccessibleTabs | components/accessible-tabs.md | 가격 계층 또는 다중 패널 뷰를 위한 WAI-ARIA 탭 전환기 | 키보드 화살표 탐색(Left/Right/Home/End) |
| 9. SocialShare | components/social-share.md | Web Share API를 사용한 개인정보 보호 우선 소셜 공유 바 | 100% GDPR 안전, 추적기 0개, 정적 의도 URL |
| 10. TableOfContents | components/table-of-contents.md | 스크롤스파이가 있는 장문 문서 목차 | IntersectionObserver 제목 추적, 문서 레이아웃과 쌍을 이룸 |
| 11. AccessibleCarousel | components/accessible-carousel.md | 리뷰, 카드 또는 로고를 위한 네이티브 CSS 스크롤 스냅 슬라이더 | 네이티브 터치 스와이프(0 KB JS), 접근 가능한 이전/다음 버튼 |
| 12. InfiniteTicker | components/infinite-ticker.md | 호버/포커스 시 일시 정지 기능이 있는 순수 CSS 무한 로고/텍스트 마키 | WCAG 2.2.2 준수, 중복 트랙이 aria-hidden으로 숨겨짐 |
| 13. StatsCounter | components/stats-counter.md | 이즈아웃 스크롤 애니메이션이 있는 HTML 우선 메트릭 카운터 바 | 0 CLS, 정적 HTML 폴백, IntersectionObserver |
| 14. AddToCalendar | components/add-to-calendar.md | 빌드 타임 iCalendar 파일에 대한 "날짜 저장" 링크 | 동일 출처 정적 .ics + <a download>, 유효한 RFC 5545, 0 KB JS |
| 15. SelfHostedMap | components/self-hosted-map.md | 자체 호스팅 PMTiles 추출 항목의 장소 목록을 지도로 표시, 번호가 매겨진 핀이 목록과 일치 | 지연 로드 MapLibre, HTTP 206 타일 라우트, 텍스트 대체물이 있는 aria-hidden 맵, 테마를 따름. npm 패키지 필요(소유자 승인) |
| 16. ClickableParent | components/clickable-parent.md | 하나의 실제 링크 또는 버튼을 통해 전체 카드/행을 클릭 가능하게 함 | ::after 확장 히트 영역, 보조 컨트롤 올림, 컨테이너의 포커스 링, 0 KB JS |
| 17. Card | components/card.md | 미디어, 메타, 본문 및 보조 작업이 있는 콘텐츠 카드 | 제목 우선 DOM, headingLevel 속성, 컨테이너 쿼리 레이아웃, 연결 시 ClickableParent 계약 |
목록에 없는 컴포넌트 결정 게이트(인간 결정 지점)
프로젝트 요구사항이나 디자인이 위의 17개 목록화된 컴포넌트에 없는 인터랙티브 UI 컴포넌트를 요청하는 경우(예: Before/After 이미지 비교 슬라이더, 날짜 선택기, 범위 선택기, 단계별 마법사 또는 사용자 정의 미디어 플레이어):
[!IMPORTANT] 멈추고 질문하세요: 에이전트는 클라이언트 측 프레임워크 라이브러리(React, Vue, Svelte)를 절대 자동으로 설치해서는 안 되며, 검증되지 않은 타사 npm 패키지를 가져오거나 임시 텍스트 플레이스홀더 블록(예:
<div class="c-placeholder">)을 남겨서는 안 됩니다.에이전트는 반드시 멈추고 프로젝트 소유자에게 세 가지 명확한 선택지를 제시해야 합니다:
- 옵션 A: 사용자 정의 바닐라 컴포넌트(권장): 아래의 맞춤형 컴포넌트 폴백 계약을 준수하는 종속성 없는
.astro컴포넌트를 작성합니다.- 옵션 B: 정적 HTML 기본: 0 KB JavaScript로 완전히 정적인 의미론적 레이아웃(예: 나란히 이미지 또는 표준 스택형 카드)을 구현하고, 인터랙티브 향상을 완전히 생략합니다.
- 옵션 C: 카탈로그 패턴 적응: 기존 카탈로그 패턴이 요구사항을 충족할 수 있는지 평가합니다(예:
AccessibleModal을 이미지 라이트박스로, 또는AccessibleTabs를 단계별 패널 뷰로 적응).
맞춤형 컴포넌트 폴백 계약
프로젝트 소유자가 목록에 없는 컴포넌트(옵션 A) 구축을 승인하는 경우, 구현은 다음 여섯 가지 규칙을 충족해야 합니다. 프레임워크 적응의 경우 항목 3-4에 대해 프레임워크의 구성, 클래스 이름 지정 및 토큰 규칙을 사용하세요:
- 의미론적 HTML 우선: JavaScript를 작성하기 전에 표준 HTML 요소에 인터페이스를 고정하세요(예: 슬라이더의
<input type="range">, 공개의<details>, 오버레이의<dialog>). - 외부 런타임 종속성 제로: 클라이언트 프레임워크 런타임(React/Vue 없음) 및 타사 UI 위젯 패키지 제로. 브라우저 인터랙션이 진정으로 필요할 때만 순수 바닐라 TypeScript/JavaScript를 작성하세요.
- 범위 지정 BEM 및 CSS 논리 속성: 표준 BEM 이름 지정(
.c-block,.c-block__element) 및 흐름 상대 레이아웃 속성(inline-size,block-size,padding-block,margin-inline,inset)을 사용하세요. - 폴백이 있는 네임스페이스 토큰: 16진수 값을 하드코딩하지 마세요. 합리적인 폴백과 함께 호스트 의미론적 토큰 또는 네임스페이스 사용자 정의 속성을 사용하세요(
var(--comp-color, var(--color-primary))). - JavaScript 없는 점진적 향상: 클라이언트 JavaScript가 비활성화된 경우에도 컴포넌트는 읽기 쉽고 접근 가능하며 작동 가능해야 합니다.
@media (scripting: none)또는 네이티브 CSS 폴백 레이아웃(예: 나란히 또는 스택형 뷰)을 사용하여 콘텐츠가 숨겨지지 않도록 하세요. - WCAG 2.2 AA 준수: 최소
44px(2.75rem) 터치 대상, 고대비 가시적인:focus-visible링, 명확한 접근 가능한 이름(aria-label,<label>)을 유지하고 0개의 axe-core 위반을 확인하세요.
에이전트를 위한 선택적 로드 지침
사용자가 위 컴포넌트 중 하나를 구현하거나 편집하도록 요청하는 경우 전체 카탈로그를 읽지 마세요. 대신 필요한 특정 컴포넌트 파일만 읽으세요(예: components/accessible-carousel.md).
통합 확인
빌드/배포된 출력에서 선택된 사양을 확인하세요: 의미론 및 이름, 키보드/포커스 동작, 상태 전환, JavaScript 없음 처리, 반복 초기화 및 호스트 토큰 매핑. 독립 실행형 패키징 규칙은 독립 실행형 컴포넌트에만 적용됩니다. 프레임워크는 기본 요소를 재사용합니다. 프로젝트의 구성된 검사/빌드/테스트를 실행하고 사용할 수 없는 검사 또는 적용 범위 격차를 공개하세요. 44px는 이 라이브러리의 대상 크기 규칙이며 WCAG AA 임계값 자체가 아닙니다.
네이티브 선택 팝업은 소유자가 사용자 정의 콤보박스의 장단점을 승인하지 않는 한 브라우저/OS UI로 유지됩니다.