공통 가이드
공유 토큰만 쓰는 컴포넌트 규칙 — DESIGN.md 의 Components 절
이 파일(DESIGN.md)은 brand-agnostic 공유 baseline이라 컴포넌트 스펙은 brand 파일(DESIGN.hr.md / DESIGN.desk.md)에 작성합니다 — primary 등 brand 토큰을 직접 참조해야 자연스러운 표현이 되기 때문(spec이 cross-file {colors.X} reference 미지원).
본 파일에서는 brand-neutral 컴포넌트(divider, page text, caption, chart color 등 — 공유 토큰만 사용)만 정의하고, brand-specific 컴포넌트(Button, Focus ring 등)는 brand 파일에서 자체 prose로 작성합니다.
Button
수치 · 규칙의 원본은 specs/components/button.md · specs/components/button.yaml 이다 — 2026-09-30 SEED Action Button 구조로 다시 썼다(v112). 이 절은 토큰과 닿는 자리만 모은다.
변형과 색
| 변형 | 쓰는 곳 | 바탕 → 누름 · 호버 | 글자 · 아이콘 |
|---|---|---|---|
| brandSolid | 서비스 핵심 액션 하나(Desk 거래 추가 · HR 휴가 신청) | 브랜드 채움 → 브랜드 누름(브랜드 파일) | static-white |
| neutralSolid (기본) | 대부분의 CTA — 저장 · 확인 · 다음 | bg-neutral-inverted → bg-neutral-inverted-pressed | fg-neutral-inverted |
| neutralWeak | CTA 옆 보조(취소) · CTA 를 뺀 대부분의 액션 | bg-neutral-weak → bg-neutral-weak-pressed | fg-neutral |
| criticalSolid | 되돌릴 수 없는 작업의 확정(주로 Alert Dialog) | bg-critical-solid → bg-critical-solid-pressed | static-white |
| brandOutline | Solid 보다 낮은 위계 — neutralOutline 과 짝 | 투명 + stroke-neutral-weak 1px → bg-layer-default-pressed | 브랜드 글자(브랜드 파일) |
| neutralOutline | 가장 낮은 위계의 보조 액션 | 투명 + stroke-neutral-weak 1px → bg-layer-default-pressed | fg-neutral |
| ghost | 메뉴 · 툴바 · 목록의 가벼운 액션 | 투명 → bg-layer-default-pressed | fg-neutral · fg-neutral-subtle · 브랜드 글자 · fg-critical |
브랜드마다 달라지는 건 브랜드 채움 · 누름과 브랜드 글자뿐이다 — 값과 대비는 DESIGN.hr.md · DESIGN.desk.md 의 Button 절. 한 화면의 Solid 버튼은 하나, 확인 창을 여는 삭제는 ghost + fg-critical 이다.
대비(라이트 · 다크, 글자 × 바탕):
| 조합 | 라이트 | 다크 |
|---|---|---|
| neutralSolid | 16.41:1 | 13.42:1 |
| neutralSolid 누름 | 7.11:1 | 7.70:1 |
| neutralWeak | 15.20:1 | 10.32:1 |
| criticalSolid | 5.06:1 | 5.77:1 |
ghost fg-neutral-subtle × bg-layer-default | 5.50:1 | 6.09:1 |
ghost fg-critical × bg-layer-default | 5.06:1 | 6.08:1 |
모두 본문 4.5:1 을 넘는다. Outline 테두리(stroke-neutral-weak × bg-layer-default 1.23:1)는 글자가 버튼을 알려 주므로 1.4.11 대상이 아니다 — SEED 도 같다.
상태
| 상태 | 표현 |
|---|---|
| hovered | 누름 색(v106) — 마우스 기기에서만, 축소는 없다 |
| pressed | 누름 색 + 세로 2px 거리 축소(v104 — Motion 의 눌림 피드백). 축소는 motion-duration-pressed-scale · motion-ease-pressed-scale, 색은 motion-duration-color-transition · motion-ease-easing |
| focused | stroke-focus-ring 2px · 띄움 2px(v106) — 키보드 포커스(focus-visible)에만 |
| loading | 누름 색 위 로딩 원(Outline 은 투명 그대로), 라벨 자리 폭 유지 · 누르기를 막고 aria-busy="true" |
| disabled | bg-disabled · fg-disabled(2.93:1 — 1.4.3 incidental 예외). 불투명도로 흐리게 하지 않는다(v106) |
크기
| 크기 | 높이 | 좌우 여백 | 글자 | 모서리 | 아이콘 |
|---|---|---|---|---|---|
| xsmall | 32px | spacing-x3_5 (14px) | t3 13px | radius-full (알약) | 14px |
| small | 36px | spacing-x3_5 (14px) | t4 14px | radius-r2 (8px) | 14px |
| medium (기본) | 40px | spacing-x4 (16px) | t4 14px | radius-r2 (8px) | 16px |
| large | 48px | spacing-x5 (20px) | t6 18px | radius-r3 (12px) | 22px |
글자 굵기는 모두 700. 아이콘만 있는 버튼은 정사각(높이 = 폭)이다. 크기는 이름이 아니라 높이로 고른다 — 모달 footer 는 small, 모바일 하단 CTA 는 large.
누르는 영역 · 배치
- 누르는 영역은 보이는 크기와 따로 44 × 44 까지 넓힌다(v106) — 2.5.5 (AAA 44 × 44) 충족.
- 2.5.8 (AA 24 × 24) 은 모든 크기가 충족한다.
- 나란히 두는 버튼 사이는 8px, 셋까지. 화면 하단에 채운 두 버튼(닫기 · CTA)은 3:7 — 모달 footer 는 Dialog · Drawer 의 폭 나누기(지금은 균등)를 따른다.
Accessibility 체크리스트
- keyboard:
Enter/Space로 누르고Tab으로 포커스가 들어온다 - 아이콘만 있는 버튼은
aria-label필수 - 로딩은
aria-busy="true"— 포커스는 그대로 두고 누르기만 막는다 - 비활성:
aria-disabled="true"는 포커스가 남고,disabled속성은 포커스를 뺀다 — 흐름에 맞춰 고른다
Input · Textarea
수치 · 규칙의 원본은 specs/components/input.md · input.yaml(한 줄 — SEED Text Input)과 textarea.md · textarea.yaml(여러 줄)이다 — 2026-10-01 SEED Text Input · Textarea 구조로 다시 썼다. 라벨 · 설명 · 오류 · 글자 수는 Field(아래 Field 절)가 둘레에서 그린다. 이 절은 토큰과 닿는 자리만 모은다.
모양과 색
| 요소 | 값 |
|---|---|
| 바탕 | 투명 — 놓인 표면(bg-layer-default · bg-layer-floating)이 비친다 |
| 테두리 | 안쪽 1px stroke-neutral-weak. 밑줄형은 아래만 |
| 포커스 | 안쪽에 2px stroke-neutral-contrast 를 덧그린다 — 마우스 · 터치로 눌러도(입력 중). 내용은 밀리지 않는다. 읽기 전용이면 없다 |
| 오류 | 안쪽 2px stroke-critical-solid — 포커스해도 그대로 |
| 비활성 | 바탕 bg-disabled · 글자 · 아이콘 fg-disabled. 불투명도로 흐리게 하지 않는다(v106) |
| 읽기 전용 | 바탕 bg-disabled · 값은 fg-neutral 그대로(밑줄형은 바탕 없이 값 fg-neutral-muted) |
| 값 · placeholder | fg-neutral · fg-placeholder |
| 앞 · 뒤 글자 · 아이콘 · 지우기 | fg-neutral-subtle · fg-neutral-muted · fg-neutral-subtle |
덧그린 2px 의 색만 motion-duration-d2 (100ms) · motion-ease-easing 로 바뀐다 — 두께는 바로 바뀐다(SEED).
대비(라이트 · 다크, bg-layer-default 위): 값 16.41 · 13.42, 앞뒤 글자 5.50 · 6.09, placeholder 4.18 · 4.13(v119 — 4.5:1 밑, 사용자 결정 2026-10-16 글자 역할 D7), 포커스 테두리 16.41 · 13.42, 오류 테두리 5.06 · 6.08. 1px stroke-neutral-weak(1.23 · 1.56)는 칸을 알리는 유일한 표시가 아니다 — 라벨 · placeholder 가 함께 알린다(SEED 와 같다). lint 대비 쌍 input-light · input-dark(본문 × surface-input)는 읽기 전용 칸(값 × bg-disabled — 같은 색)을 잰다.
크기
| 크기 | 높이 | 좌우 여백 | 글자 | 모서리 | 아이콘 · 지우기 |
|---|---|---|---|---|---|
| large | 52px | spacing-x4 (16px) | t5 16px | radius-r3 (12px) | 20 · 22 |
| medium | 40px | spacing-x3_5 (14px) | t4 14px | radius-r2 (8px) | 16 · 18 |
| underline large | 40px(위아래 8) | 0 | t6 18px | 0 | 24 · 22 |
| underline medium | 34px(위아래 6) | 0 | t5 16px | 0 | 20 · 18 |
- 웹의 기본은 반응형 — 1280 미만 large, 이상 medium(SEED
lg). 앱은 늘 large. medium 은 데스크톱 웹(마우스)에서만 — 폰에서 40 은 누르는 영역 44(AAA)에 못 미친다. 한 폼 안에서 크기를 섞지 않는다. - Textarea 는 상자형 하나 — 자동 높이 3줄(large 94 · medium 82, 위아래 14 · 12)에서 쓴 만큼 자라고, 끄면 2줄(72 · 62) 이상 고정 높이에서 칸 안 스크롤. 손잡이(resize)는 두지 않는다.
쓰는 규칙
- 밑줄형은 화면에 입력이 하나뿐일 때(금액을 먼저 받는 화면 · 목록 위 검색 · 초대 코드 · 잠금 해제).
- 단위는 칸 안 뒤 글자로 — 라벨에 "(원)" 을 붙이지 않는다. 금액은 숫자 키보드 · 천 단위 쉼표,
type="number"는 쓰지 않는다. - 고르는 값(날짜 · 시각 · 카테고리 · 자산)은 타이핑으로 받지 않는다 — Input Button 으로 시트 · 달력 · 목록을 연다.
- 형식이 정해진 값(전화번호 · 주민등록번호)은 칸을 나누지 않는다 — 한 칸에서 형식을 맞춰 준다.
- 지우기 버튼은 검색칸 · 선택 사항인 칸에, 값이 있을 때만(이름 "지우기").
Accessibility 체크리스트
- 모든 칸에 라벨(Field) — placeholder 를 이름으로 쓰지 않는다
- 오류면
aria-invalid, 설명 · 오류 · 글자 수 · 단위 글자는aria-describedby - 포커스하면 테두리가 2px 로 짙어진다(키보드 · 마우스 모두)
- 최대 글자 수는 자소 단위로 세고, 한글은 조합이 끝난 뒤 자른다
Select · Input Button
수치 · 규칙의 원본은 specs/components/select.md · select.yaml(짧은 선택지를 칸 아래 목록으로 — SEED Select)과 input-button.md · input-button.yaml(입력칸 모양의 버튼 — 시트 · 팝오버를 연다, SEED Input Button)이다 — 2026-10-01 사용자 결정. 라벨 · 설명 · 오류는 Field(아래 Field 절)가 둘레에서 그린다. 이 절은 토큰과 닿는 자리만 모은다.
나누기
| 이런 자리 | 컴포넌트 |
|---|---|
| 짧은 선택지 5개 이상(한 줄 설명까지)에서 폼 값을 고른다 | Select — 칸 아래 목록. 폰에서도 시트로 바꾸지 않는다 |
| 달력 · 시각 · 아이콘 격자 · 검색해 고르는 긴 목록 | Input Button — 1280 미만 아래 시트 · 이상 칸 아래 팝오버 |
| 설명 · 그림 · 딸린 입력이 붙는 2 ~ 6개를 견줘 고른다 | Select Box |
| 2 ~ 4개 짧은 선택지 | Chip — 글이 길면 Radio · Checkbox |
트리거 · 칸
상자는 Input 의 상자형과 같다 — large 52 · medium 40 · 웹 기본 반응형(1280), 앱은 large. 모서리 radius-r3 · radius-r2, 투명 바탕 + 안쪽 1px stroke-neutral-weak, 오류 안쪽 2px stroke-critical-solid, 비활성 · 읽기 전용 bg-disabled(흐림 없음 — 읽기 전용의 값은 진한 글자). 버튼이라 Input 과 다른 자리:
| 요소 | 값 |
|---|---|
| 누름 · 호버 | 바탕 bg-layer-default-pressed + 값 · 아이콘만 2px 거리 축소(v104). 마우스는 호버에 같은 바탕 |
| 포커스 | 키보드 포커스에만 바깥 링 2px · 띄움 2px stroke-focus-ring |
| 셰브론(Select) | 20 · 16 fg-neutral-muted, 열리면 180°(열 때 motion-duration-d3 · 닫을 때 motion-duration-d2) |
| 뒤 아이콘(Input Button) | 무엇이 열리는지 — 달력 · 시계 · 아래 화살표 |
| 지우기(Input Button) | 선택 사항인 칸에 값이 있을 때만, 22 · 18 fg-neutral-subtle — 값 뒤 · 뒤 붙이개 앞 |
목록(Select)
| 요소 | 값 |
|---|---|
| 목록 | 트리거 폭 · 아래 8(모자라면 위) · 모서리 radius-r5 · bg-layer-floating · shadow-s3 · 위아래 8 · 높이 min(480, 남은 화면 — 200 은 둔다) |
| 선택지 | large 46 · medium 39(설명이 있으면 66 · 57) · 좌우 16, 글 t5 · t4 fg-neutral, 설명 t3 · t2 fg-neutral-subtle |
| 고른 표시 | 오른쪽 체크 14 · 12(선 2.5) fg-neutral — 바탕 · 굵기는 바꾸지 않는다 |
| 누름 · 호버 · 키보드 위치 | 좌우 8 들인 알약(모서리 12) bg-layer-floating-pressed — 누르는 동안만 콘텐츠 2px 거리 축소 |
| 묶음 | 제목 t4 500 · t3 400 fg-neutral-subtle, 묶음 사이 1px stroke-neutral-subtle(좌우 16 들임 — 8 + 1 + 8) |
| 모션 | 열 때 motion-duration-d3 · motion-ease-enter(0.95 → 1 · 투명 → 불투명), 닫을 때 motion-duration-d2 · motion-ease-exit |
쓰는 규칙
- 늘 Field 의 라벨과 함께. placeholder 는 "{값의 종류} 선택".
- "없음" 이 답이면 "{칸 이름} 없음" 선택지를 맨 앞 따로 묶음에 — Select 에는 지우기 버튼이 없다. 꼭 골라야 하는 칸은 없음 없이 제출 때 오류, 늘 값이 있는 칸은 기본값을 골라 둔다.
- 여럿 고르기는 열린 채 이어 고른다 — 칸에는 "식비, 교통", 넘치면 "식비 외 2개". 최대 개수는 Field 설명에, "전체 선택" 같은 선택지는 두지 않는다.
- 선택지 글은 명사형으로 짧게 — 코드값(Y · N · ANNUAL)을 내지 않는다. 폼 값을 탭으로 고르지 않는다. 요일 7개도 여럿 고르는 Select.
- Input Button 은 혼자 쓰지 않는다 — 늘 고르는 자리를 연다. 달력 · 시각은 "완료" 로 넣고(고르는 동안 칸의 값은 그대로), 목록은 누르면 바로 넣는다. 긴 목록은 검색 시트(Combobox 를 두지 않는다).
Accessibility 체크리스트
- 모든 칸에 라벨(Field) — placeholder 를 이름으로 쓰지 않는다. 라벨을 누르면 포커스만(열지 않는다)
- Select 트리거
role="combobox"·aria-expanded, 목록role="listbox"· 선택지role="option" aria-selected· 짚은 선택지aria-activedescendant - Input Button 이름은 라벨 + 고른 값,
aria-haspopup="dialog"·aria-expanded, 필수는 설명으로 "필수" - 키보드 포커스 링 — 트리거 · 칸
- large 52 · 선택지 46 은 AAA 44 ✓, medium 은 1280 이상 데스크톱(마우스)에서만
Card
2026-10-08 — 원본은
specs/components/card.md·card.yaml(SEED 면 · Feedback). 옛 변형 넷(default · interactive · outline · flat) · 여백 네 단계 · 모서리 8 · hover 그림자 상승은 걷었다.
회색 바닥(bg-layer-basement) 위 흰 면(bg-layer-default) + 1px stroke-neutral-weak, 그림자 없음 — 폰 · 데스크톱 · 라이트 · 다크가 같은 규칙이다(사용자 결정 — 데이터 표시 비교 페이지 4A · 5A · 6B · 7A · 8B).
| 자리 | 값 |
|---|---|
| 모서리 | 16(radius-r4) — 카드 안 목록의 누름 바탕은 10(동심 모서리) |
| 여백 | 24(spacing-x6) — 폭과 상관없이. List 줄 · Bottom Sheet 와 같은 값이다(카드 24 = 줄 24 = 시트 24). 목록 카드는 좌우 0 — 줄이 제 좌우 24 를 갖고, 머리 위 · 좌우 24, 카드 아래 12(줄 12 와 합쳐 24) |
| 카드 사이 | 위아래로 쌓으면 8(spacing-x2 — SEED "8px Gap"), 데스크톱 격자 칸 사이는 layout-gutter 24 |
| 머리 | 제목 16 / 22 · 700 · fg-neutral + 오른쪽 동작 하나("전체 보기" — 글 버튼: 14 · 700 · fg-neutral-muted · 보이는 36 · 꺾쇠 없음, 누르는 영역 44. Typography 의 "글자 역할" R16 — 2026-10-16 사용자 결정 D2 로 6B 의 14 · 500 · subtle + 꺾쇠를 바꿨다) |
| 누름 | 면 bg-layer-default-pressed + 2px 거리 축소 — 안에 대등한 동작이 있으면 색만(SEED Feedback). 그림자 상승 · 위로 뜨기 없음 |
| 지표 카드 | 라벨 13 · 500 · fg-neutral-subtle · 숫자 24(데스크톱 격자에 셋 · 넷씩이면 20) · 700 · 고정폭 숫자 · 증감 줄(Colors 의 "증감 — 방향 색") — 폰은 한 줄에 하나, 숫자 굴림 애니메이션 없음 |
| 순자산 카드 | Desk 홈 · 자산 한 자리 — 브랜드 채움 135° + 흰 글자, 다크도 짙은 채움 · 증감도 흰 ▲ · ▼(Desk 파일의 Card 절) |
| 카드 안 아코디언 | 카드 상세의 혜택 · 유의사항(2026-10-10) — 좌우 0 · 머리 위 · 좌우 24 · 아래 4, 카드 아래 8(마지막 트리거 16 과 합쳐 24) · 머리 오른쪽에 모두 펼치기 |
- 변형은
default·hero둘이다. 그림자 카드 · 흰 위 흰 그림자 카드(raised) · 회색 채움(muted) · 브랜드 틴트(brand)는 두지 않는다 — 시트 · 대화상자 안의 요약은 List 키-값 줄 · Callout. - 카드 안에 카드를 두지 않는다. 카드의 데이터를 못 불러오면 그 카드 안에 Result Section
medium+ 다시 시도 — 화면 전체를 스켈레톤으로 되돌리지 않는다. card-light·card-dark짝(흰 면 · 다크 면 위 본문 글자)은 lint 가 대비를 재는 자리로 남긴다.
Page text
기록 — 기준은 Typography 의 "글자 역할"(2026-10-16)이다: 화면 제목 R1 · 화면 부제 R2 · 구역 제목 R4 · 긴 글 R11. 옛 내용(body-md 15 · 600 강조 · title-sm ~ title-md 헤딩 위계)은
DESIGN.history/v119-text-roles.md에 있다.
Caption
기록 — 기준은 Typography 의 "글자 역할"(2026-10-16)이다: 줄 · 칸 안 설명 · 메타는 R9(
fg-neutral-subtle한 색 — 메타 줄은 Tag Group,specs/components/tag-group.md), 축 · 단위 · 범례 같은 덧붙인 정보는 R10. 옛 secondary / tertiary 위계(카테고리 muted · 시각 subtle)는 쓰지 않는다 —DESIGN.history/v119-text-roles.md.
Badge · Notification Badge · Tag Group
2026-10-03 SEED Badge · Notification Badge · Tag Group 구조로 다시 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/4ySVacsdnG4fgraR1HRK3G, 1A · 2A · 3A · 4A 와 "따라오는 것"). 수치 원본은
specs/components/badge.yaml·notification-badge.yaml·tag-group.yaml, 쓰는 규칙은 같은 이름의.md다. 옛 Badge 절(채운 의미 색 넷 · 18 · 22 · 28 · 알약 또는 모서리 4 · 개수는aria-live)은 걷었다 — 옛 스펙은specs/components/badge.history/v-pre-seed-display.*. 머리말의badge-success·badge-error·badge-warning·badge-info대비 쌍은 solid 배지의 흰 글자(라이트)를 잰다. 의미 색 outline 의 옅은 테두리 넷(stroke-critical-weak·stroke-positive-weak·stroke-warning-weak·stroke-informative-weak)을 이 묶음에서 들였다(v117).
나누기
| 보이려는 것 | 쓰는 것 |
|---|---|
| 대상의 상태 · 분류(예정 · 연체 · 승인 · 신용) | Badge — 누르지 않는다 |
| 설명 줄의 메타(카테고리 이름 · 자산 · 시각 · 거리 · 개수 · 금액) | Tag Group — " · " 로 이은 글줄 |
| 안 읽은 알림이 있음 · 몇 개 | Notification Badge — 점 · 숫자 |
| 고르기 · 거르기 · 넣은 값 빼기 | Chip — 누르는 알약(Chip 절) |
모양
| Badge | Notification Badge | Tag Group | |
|---|---|---|---|
| 크기 | medium 20(좌우 6 · 위아래 2 · 글 11/15) · large 24(8 · 4 · 12/16), 앞 아이콘 12 · 14 | 점 6 · 숫자 18(좌우 4 · 11/15 · 700 — 글자 크기 설정을 따르지 않는다) | 12/16(기본) · 13/18 · 14/19, 아이콘 12 · 13 · 14 |
| 모양 | 둥근 사각 — 모서리 radius-r1 4 · radius-r1_5 6. 알약은 Chip 에만 | 원 · 알약 | 글 — 항목 사이 " · " 글자(앞 항목에 붙는다) |
| 색 | weak bg-*-weak + fg-*-contrast · 500 / solid bg-*-solid + static-white · 700 / outline 투명 + 안쪽 1px stroke-*-weak + fg-* · 700. 중립은 bg-neutral-weak + fg-neutral-muted · bg-neutral-inverted + fg-neutral-inverted · stroke-neutral-weak, warning solid 는 주황 + 흰 글자 | 점은 브랜드 글자색(다크에서 밝은 짝), 숫자는 브랜드 채움 + 흰 글자 — 브랜드 파일 | 기본 fg-neutral-subtle(흰 바탕 5.50) · 앞세울 항목 fg-neutral 700 · 구분 fg-disabled |
| 자리 | 줄 · 상세 머리 — 한 대상에 둘까지, 사이 4 | 아이콘 상자 기준 — 점 오른쪽 위 안쪽 1(24 아이콘 x 17 ~ 23 · y 1 ~ 7), 숫자 왼쪽 아래 꼭짓점 (아이콘 폭 − 8, 14). 글이면 끝 + 2 · 줄 상자 위 | List 의 설명 줄 · 카드 · 상세 머리의 메타 |
쓰는 규칙
- 배지는 누르지 않는다 — 누르는 라벨은 Chip(알약). 배지의 뜻을 더 알려야 하면 옆에 ⓘ Help Bubble.
- 반복되는 목록은 weak — 한 목록 안은 한 변형, 뜻은 톤으로. brand 는 요금제 · 본인 표시처럼 브랜드와 닿는 자리에만.
- 흰 표면 위에 — 중립 weak 의 바탕은 회색 바탕(
bg-layer-basement)과 같은 색이라 거기서 사라진다. - 합계에 안 드는 줄(예정 · 환불)은 흐리지 않는다 — 제목 · 금액만
fg-neutral-subtle, 환불 금액은 취소선, 배지는 보통 대비(List 절). - 알림 점 · 숫자는 확인할 새 것에만 — 보면 사라진다. 0 은 안 보이고 100 이상은 "99+". 한 화면에 아껴서(여러 탭에 동시에 달지 않는다).
- 메타 줄 구분은 " · " 글자 — 2px 점 그림 · "•" 를 쓰지 않는다. 항목은 6 ~ 10자, 한 묶음은 한 크기.
- 글 — 배지 · 메타에 영어 · 코드값을 내지 않는다("NEW" → "새로",
ROLE_ADMIN→ "관리자", "Day 2 of 3" → "2/3일째", "9:00 AM" → "오전 9:00"). 요금제 이름 Pro · Free 는 그대로.
접근성
- Badge: 역할 없는 글 — 줄 이름에 이어 읽힌다. 뜻은 글이 말하고 색은 거든다. 모든 짝이 4.5:1 이상이다.
- Notification Badge: 점 · 숫자는 숨기고 붙은 버튼 · 탭 이름에 넣는다("알림, 새 알림 3개"). 수가 바뀌어도 소리로 알리지 않는다(라이브 영역 없음).
- Tag Group: 구분 " · " 는 숨기고 그 자리에 보이지 않는 ", " — 항목마다 끊어 읽는다. 뜻이 있는 아이콘 항목은 읽을 글("분할 2건")을 준다.
Alert text
기록 — 기준은 Callout(
specs/components/callout.md— 2026-10-02, 본문 t4 · 제목 700 · 톤 contrast 색)과 Field 오류(Typography 의 "글자 역할" R19 — t4 ·fg-critical+ 아이콘)다. 옛 alert-text 짝 · body-md 15 · 600 제목은DESIGN.history/v119-text-roles.md에 있다.
Focus ring
모든 인터랙티브 컴포넌트(button / input / card-interactive / link / tab 등)의 focus 표현 통일 — 키보드 사용자의 시각적 navigation cue.
Mode pair (sparse — brand 토큰이 contrast 검증 담당)
- focus-ring-on-light (
focus-ring-on-light): 라이트 표면 위 focus - focus-ring-on-dark (
focus-ring-on-dark): 다크 표면 위 focus
(색은 역할 색 stroke-focus-ring 하나다(v102) — 라이트 · 다크 값은 brand 파일의 v102 표, 그룹 화면은 이 파일의 짙은 회색(2026-10-23 "그룹 색 · 로고 칠"). 옛 border-focus · border-focus-light 는 같은 값의 별칭이다.)
Spec
- 두께: 2px outline (1px은 시인성 부족)
- offset: 컴포넌트 외곽 2px (즉 컴포넌트 + 2px gap + 2px ring → 총 4px 외곽 영역 — v106, 스펙 다수와 맞춤)
- 입력칸 · 선택 상자: 입력 중에는 링 대신 같은 색의 테두리 2px(v106 — State 절)
- shape: 컴포넌트 outline 100% 둘러쌈 —
border-radius동일 적용 - trigger:
focus-visiblepseudo만 (마우스 클릭 시 미표시, Tab/keyboard로 진입 시만)
WCAG 검증
- 2.4.11 Focus Appearance (AA — 2.2): focus indicator는 (a) 인접 표면 대비 3:1 이상, (b) 컴포넌트 외곽선 둘레의 최소 2 CSS pixel 두께 + 인접한 비-focus 상태 대비 3:1 충족 — 본 시스템 모두 충족
- 2.4.12 Focus Not Obscured (Minimum) (AA — 2.2): focus 받은 요소가 author-created 컨텐츠에 의해 완전히 가려지면 안 됨 — sticky header / popup overlay 디자인 시 z-index + scroll-margin 고려
- 2.4.13 Focus Appearance Enhanced (AAA — 2.2): 컴포넌트 둘레 둘레 100% × 두께 4 CSS pixel 또는 기준 2배 이상 대비 권장 — 향후 enhanced focus 옵션 (
focus-ring-enhanced토큰) 추가 후보
사용 예시 (CSS 의사코드)
.button:focus-visible {
outline: 2px solid var(--color-stroke-focus-ring); /* 다크 값은 다크 블록이 바꾼다 */
outline-offset: 2px;
}Layout
- focus ring은
outline사용 (box-shadow도 가능하지만 outline이 layout shift 없음 — focus 시 element 크기 안 변함) - offset 2px → outline-offset: 2px (v106)
Motion
- focus ring 등장:
motion-duration-color-transition×motion-ease-easing(opacity 0 → 1) — v106, v104 이름으로 prefers-reduced-motion: reduce시 즉시 표시 (focus 인지 지연은 a11y 저해)
Accessibility 체크리스트
- 2.4.11: 모든 컴포넌트의 focus state는
focus-ring-on-{light,dark}토큰 사용 -
focus-visible만 사용 — 마우스 사용자 방해 없음 (:focus로 일관 적용 시 클릭 후에도 ring 표시되어 산만) - 2.4.12: focus 가려짐 방지 — sticky header 아래 focus 받으면 자동 scroll 보강 (
scroll-margin-top: <header height>) - 다크 모드 자동 전환:
[data-theme="dark"]또는prefers-color-scheme: dark블록이--color-stroke-focus-ring을 다크 값으로 바꾼다
Divider
2026-10-03 SEED Divider 로 다시 정했다(옛 Separator 를 대신 — 사용자 결정, 비교 페이지 https://claude.ai/artifact/4ySVacsdnG4fgraR1HRK3G 의 "따라오는 것"). 수치 원본은
specs/components/divider.yaml, 쓰는 규칙은divider.md다. 옛 절(border-default1px · dashed 예약 · margin-only)은 걷었다 — 옛 스펙은specs/components/separator.history/v-pre-seed-display.*. 머리말의divider-light·divider-dark는 옛 v40 짝(값은 옛border-default)이고, 글자가 없어 대비 검사 대상이 아니다.
| 세기 | 쓰는 것 | 자리 |
|---|---|---|
| 약함 | 들인 선 — 양끝 16 | 같은 묶음 안 |
| 중간 | 끝까지 선 | 묶음 사이 · 액션 영역 위 · 스크롤되는 본문 위 머리 |
| 강함 | 8 간격 — 회색 바탕(bg-layer-basement) 위 흰 층(bg-layer-default) 사이. 선이 아니다 | 크게 다른 내용 사이 |
- 선은 하나 — 1px
stroke-neutral-subtle(흰 바탕 1.15 · 다크 1.30, SEED 기본 neutral-muted 와 같은 진하기 — 새 토큰 없이). 굵은 선 · 짙은 선 · 점선 · "8px 구분선" 을 두지 않는다. - 가로(부모 폭) · 세로(부모 높이 — 통계 세 칸 사이). 바깥 여백이 없다 — 간격은 쓰는 자리가 정한다.
- 반복되는 목록 줄 사이는 List 의 줄 사이 선(기본 없음 · 같은 색 · 들임 24). 화면 · 묶음의 마지막 아래에는 두지 않는다.
- 기본은 장식(보조 기술에 숨김) — 이름 있는 구획을 나눌 때만
role="separator"(SEED 는<hr>가 기본). - 웹 · 앱의 border-subtle 과 border-default 가 같은 값이라 "옅은 구분선" 이 효과가 없다 — 구분선은 이 한 색으로 정리한다.
Outline (border 시각 요소 · 기록 — 기준은 Dialog · Popover 스펙과 v104 의 선)
border-strong 토큰을 1px element의 배경색으로 사용 — 외곽선이 카드/section의 외곽 식별 강도를 높일 때.
Mode pair
outline-strong-light(outline-strong-light):border-strong(#7D8593) 사용outline-strong-dark(outline-strong-dark):border-strong-dark(#838997) 사용
Spec
- 두께: 1px (border CSS 또는 1px element)
- 색상:
border-strong(default border보다 강한 식별)
사용 시나리오
- modal/dialog 외곽선 (
shadow-xl+outline-strong-light1px) — focus 가려짐 방지(2.4.12) 시 시각 분리감 보강 - highlighted card (선택된 list item, drag-over state)
- inline editor의 in-progress 표시
Contrast (UI 1.4.11)
border-strong(#7D8593) vssurface-default(#FFFFFF) = 3.34:1 ✅ UIborder-strongvsbg-page(#F5F6FA) = 3.13:1 ✅ UI (3:1 통과)border-strongvssurface-input(#F5F6FA) = 3.87:1 ✅ UIborder-strong-dark(#838997) vsbg-page-dark(#1A1F2E) = 4.68:1 ✅ UIborder-strong-darkvssurface-default-dark(#242938) = 4.13:1 ✅ UIborder-strong-darkvssurface-input-dark(#353B4D) = 4.05:1 ✅ UI
모든 표면에서 UI 1.4.11 (3:1) 통과 — 단순 외곽선만으로 컴포넌트 식별 가능.
Accessibility
- 1.4.11: 위 contrast 충족 — outline-strong은 외곽선 단독 식별 가능 (
border-default1.16:1과 다름) - 다크 모드에서 modal에
outline-strong-dark+shadow-xl-dark동시 사용 권장 (다크 표면 위 elevation 보강)
Disabled label (기록 — 기준은 v106 상태 — 막힌 글자 fg-disabled · 바탕 bg-disabled, 불투명도를 쓰지 않는다)
비활성 상태 컴포넌트(disabled button/input/menu item)의 텍스트 라벨. WCAG 1.4.3 incidental 예외 명시 — 사용 불가 컴포넌트 텍스트는 본문 4.5:1 비대상.
Mode pair (sparse — textColor만 정의, backgroundColor 없음)
disabled-label-light(disabled-label-light):text-disabled(#8A91A0)disabled-label-dark(disabled-label-dark):text-disabled-dark(#838997)
contrast 참고 (incidental 예외라 통과 비대상):
text-disabled(#8A91A0) onsurface-default(#FFFFFF) = 약 3.16:1 (본문 4.5:1 미달, AA UI 3:1 통과 — 시인성은 있되 본문 의도 아님)text-disabled-dark(#838997) onsurface-default-dark(#242938) = 약 4.13:1 (동일 패턴)
의도
WCAG 1.4.3 (Contrast Minimum)의 명시적 예외:
Text or images of text that are part of an inactive user interface component, that are pure decoration, that are not visible to anyone, or that are part of a picture that contains significant other visual content, have no contrast requirement.
→ disabled 컴포넌트의 라벨은 인터랙션 불가 상태를 시각적으로 알리는 역할이라 일부러 약한 contrast 사용. 4.5:1 통과해버리면 active 상태와 구분이 어려워 오히려 UX 저해.
Spec
- text color:
text-disabled/text-disabled-dark - 추가 시각(v106): 불투명도를 쓰지 않는다 — 배경이 있으면
bg-disabled, 테두리는stroke-neutral-weak, cursor:not-allowed (State 절)
Layout
- disabled 컴포넌트 옆의 이유 글(예: "비활성화됨" 부가 설명)은 Field 설명과 같은 t4 · 400 ·
fg-neutral-subtle(Typography 의 "글자 역할" R9)로 4.5:1 을 지킨다 — 이 글은 incidental 예외 비대상
Accessibility
- 1.4.3 incidental 예외 — text 자체 contrast는 비대상
- 그러나 시각적 비활성 표현 보강 필수: 전용 색(
bg-disabled·fg-disabled·stroke-neutral-weak) + cursor:not-allowed (v106 — 불투명도 0.5 는 걷음) - aria:
disabledHTML 속성 (form 제어) 또는aria-disabled="true"(focus 가능, 메뉴 아이템 등) - screen reader가 "비활성화됨"이라고 읽음 — 시각적 강조 없이도 전달
- disabled 컴포넌트 옆에 reason text 권장 (예: "권한 없음", "기간 만료") — 글자 역할 R9 값으로
Chart color (palette)
data visualization(bar/line/pie/donut/heatmap)·카테고리 색상·tag 분류용 10색 palette. fill / stroke 용도 sparse 매핑(backgroundColor만, textColor 페어 비대상).
Mode pair (10색 × 2 = 20 토큰)
Light surface (surface-default 위) — 팔레트 700 단계(v110, L* 45 ~ 50):
| Token | hex | Hue |
|---|---|---|
chart-color-red | #D72323 | red |
chart-color-orange | #BE490D | orange |
chart-color-yellow | #8C7400 | yellow |
chart-color-green | #167F3F | green |
chart-color-blue | #1D6EC9 | blue |
chart-color-indigo | #5E60C8 | indigo |
chart-color-violet | #8B4DBA | violet |
chart-color-pink | #B83B7A | pink |
chart-color-brown | #9A6536 | brown |
chart-color-gray | #62697A | gray |
Dark surface (surface-default-dark 위) — chart-*-dark = 팔레트 800-dark(v110, L* 69):
| Token | hex |
|---|---|
chart-color-red-on-dark | #FF8477 |
chart-color-orange-on-dark | #FF8758 |
chart-color-yellow-on-dark | #C5A721 |
chart-color-green-on-dark | #25C062 |
chart-color-blue-on-dark | #69ABFF |
chart-color-indigo-on-dark | #99A1FE |
chart-color-violet-on-dark | #C793F3 |
chart-color-pink-on-dark | #F485B6 |
chart-color-brown-on-dark | #CF9F77 |
chart-color-gray-on-dark | #B7BDCC |
Hue 정렬 의도
red → orange → yellow → green → blue → indigo → violet → pink → brown → gray 는 표의 차례(무지개 + 보조색)다. 차트에서 색을 받는 차례는 v110 의 배정 순서(blue → green → orange → violet → pink → indigo → red → yellow → brown)이고 회색은 "기타" 전용이다 — 저장된 색이 있으면 아직 쓰지 않은 색부터(2026-10-08, specs/components/chart.md).
L 통일의 의도
모든 chart 색상은 동일한 명도 → 휘도 차이로 인한 시각 우선순위 부여 없이 hue 차이만으로 카테고리 구분. 이는 색맹 사용자(특히 적-녹 색맹)에게 부분적 도움 — 명도 차이가 없으면 고대비 hue 색상도 동일 톤으로 보일 수 있어 반드시 패턴/라벨 보강 필수.
Variant
| 사용 | Token 그룹 | 비고 |
|---|---|---|
| 라이트 표면 fill | chart-color-{hue} | bar 채움, pie slice |
| 라이트 표면 stroke | chart-color-{hue} | line 그래프 stroke |
| 다크 표면 fill/stroke | chart-color-{hue}-on-dark | 다크 모드에서 chart-{hue}-dark 사용 |
| 카테고리 tag | chart-color-{hue} | category badge, label dot |
| 작은 면 옅은 바탕(v111) | chart-{hue}-weak + 글자 chart-{hue}-contrast · 아이콘 chart-{hue} | 카테고리 타일 · 캘린더 칩 · 주식 나라 표시 |
| 넓은 면 옅은 바탕(v111) | chart-{hue}-subtle + 글자 chart-{hue}-contrast | 메모 카드 · 배너 |
Layout
- pie/donut: 10개를 넘으면 상위 9 + 회색 "기타"(v110)
- bar/column: 카테고리 ≤7 권장
- line graph: ≤5 lines (더 많으면 지표 타일로 계열을 골라 보게 — 나머지를 회색으로 칠하지 않는다)
- 범례: 선 · 막대는 차트 위 지표 타일, 도넛은 카테고리 목록(2026-10-08 —
specs/components/chart.md)
Motion
- chart entrance:
motion-duration-slow(300ms) ×motion-ease-out— 막대 grow / 선 draw 자연스럽게 - hover highlight:
motion-duration-fast(150ms) opacity 변화 prefers-reduced-motion: reduce시 즉시 표시 (애니메이션 없이)
Accessibility
- 1.4.1 Use of Color (강조): chart에서 색상 단독 의존 절대 금지 — 패턴(diagonal/dot 등) 또는 라벨 직접 표시 보강 필수. 특히 적-녹(red/green) 동시 사용 시 색맹 대응 필수
- 1.4.11 Non-text Contrast: chart element vs surface 대비 3:1 이상 —
chart-color-yellow(#8C7400) vssurface-default= 4.55:1 ✅, 가장 약한 hue도 UI 3:1 통과 - legend / data label: 각 색상 옆에 텍스트 라벨 또는 패턴 표시. 시각만으로 식별하는 chart 금지
- screen reader: chart는
<table>fallback 또는<svg role="img" aria-label="...">+ 데이터 요약 텍스트 동반 - focus: 차트 상자 하나가 초점을 받고 ← · → 로 날짜를 옮기며 툴팁을 띄운다(2026-10-08 —
specs/components/chart.md). 데이터 점마다tabindex를 두지 않는다
사용 예시 (CSS 의사코드)
.chart-bar-1 { background-color: var(--color-chart-color-red); }
.chart-bar-1[data-pattern="diagonal"] {
background: repeating-linear-gradient(45deg, var(--color-chart-color-red), var(--color-chart-color-red) 4px, transparent 4px, transparent 8px);
}
@media (prefers-color-scheme: dark) {
.chart-bar-1 { background-color: var(--color-chart-color-red-on-dark); }
}시트 · 대화상자 · 확인창 · 팝오버
수치 · 규칙의 원본은 specs/components/bottom-sheet.md · dialog.md · alert-dialog.md · popover.md 와 각 .yaml 이다 — 2026-10-02 SEED Bottom Sheet · Dialog · Responsive Dialog · Alert Dialog · Popover 구조로 새로 정했다(옛 Modal · Drawer · Alert Dialog · Popover 절을 대신한다). 이 절은 토큰과 닿는 자리만 모은다.
나누기 — 떠 있는 표면 일곱, 상황 → 고를 것
떠 있는 표면 일곱(Bottom Sheet · Dialog · Alert Dialog · Popover · Menu · Menu Sheet · Side Panel)을 고르는 표는 여기 한 벌이다 — 각 스펙은 고르는 순간 헷갈리는 짝 비교 표(Dialog ↔ Alert Dialog · Alert Dialog ↔ Menu Sheet)만 두고 이 표로 링크한다(2026-10-22 사용자 결정 3C — 떠 있는 표면 정리 페이지 https://claude.ai/artifact/YRPbWzhgD4EDdKsVioU8Zj).
| 이런 일 | 1280 미만 | 1280 이상 | 닫는 법 · 주의 |
|---|---|---|---|
| 지금 화면을 떠나지 않고 쓰는 입력 폼(거래 추가 · 수정) | Bottom Sheet | Dialog — 한 부품(Responsive Dialog)이 폭으로 바꾼다 | 바깥 · 끌기로 닫히지 않는다. 바뀐 값이 있으면 묻는다 |
| 한 건의 상세 조회(거래 상세) | Bottom Sheet | Dialog — 목록을 보면서 다뤄야 하면 Side Panel(오른쪽) | 머리 닫기 · 바깥 · Esc 로 닫힌다 |
| 칸에 넣을 값 고르기(날짜 · 시각 · 아이콘 · 긴 목록) | Bottom Sheet(Input Button) | Popover | 고르면 바로 들어가거나 "완료" |
| 트리거 옆 짧은 안내(규정 · 계산식) | Bottom Sheet | Popover | 제목 + 닫기. 몰라도 일은 할 수 있는 설명은 Help Bubble |
| Desk 데스크톱 벨의 알림 목록(768 이상) | Bottom Sheet(768 ~ 1279) | Popover — 벨 아래(2026-10-16 사용자 결정 Q-017-3b B) | 길이가 데이터에 따라 는다 — 끝 흐림 |
| 줄 · 화면의 동작 목록(수정 · 복사 · 삭제) | Menu Sheet | Menu | 고르면 닫히고 실행 |
| 되돌릴 수 없는 일의 확인(삭제 · 나가기) | Alert Dialog | Alert Dialog | 고르기 전에는 못 지나간다 |
| 꼭 알아야 할 결과 알림(지울 수 없어요) | Alert Dialog(single) | Alert Dialog(single) | 버튼 하나("확인") |
| 주 메뉴(HR 폰) | Side Panel(왼쪽) | — (사이드바) | 이동하면 닫힌다 |
| 처음부터 화면 높이를 넘는 내용 · 단계가 많은 일(자산 상세 — 2026-10-23 계좌 3-B) | 페이지 | 페이지 | 주소 · 뒤로 가기가 따라온다. 작은 화면 · 큰 글자로 넘친 시트는 본문만 스크롤(Bottom Sheet) |
오른쪽 Side Panel 은 지금 쓰는 곳이 없다(1280 미만은 Bottom Sheet). 값 · 동작은 각 스펙이 정한다 — 이 표는 고르는 법만 적는다.
모양
| 표면 | 값 |
|---|---|
| 공통 | 표면 bg-layer-floating, 딤 overlay-dim-light · overlay-dim-dark(Popover 는 딤 없음), 시트 · 대화상자 · 확인창은 그림자 없음 |
| Bottom Sheet | 최대 480 · 위 모서리 radius-r6 · 머리 위 24 · 제목 t8 22 · 700 · 설명 t5 fg-neutral-muted · 좌우 spacing-global-gutter · 닫기 28 원(bg-neutral-weak, 누르는 영역 44) · 손잡이는 스냅 높이를 둘 때만 · 넘칠 수 있는 본문은 Scroll Fog 위 20 · 아래 80 · 바닥 버튼 large 48 + 안전 영역 · motion-duration-d6 motion-ease-enter-expressive 로 올라오고 d4 exit 로 내려간다 |
| Dialog | medium 480 · large 800 · 최대 높이 80% · radius-r5 · 머리 24 · 제목 t8 · 본문만 스크롤(넘칠 수 있는 본문은 Scroll Fog — 늘 켜진 위 20 · 아래 80, 위로 스크롤하면 머리 아래 1px stroke-neutral-subtle) · 바닥 버튼 small 36 오른쪽 · d4 enter-expressive 로 1.3 배에서 줄며 나타남 |
| Alert Dialog | 최대 272 · radius-r5 · 안쪽 20 · 제목 t7 20 · 700 · 설명 t5 fg-neutral(짙은 글자) · 버튼 둘 나란히(길면 세로 · 확정 위) — 1280 미만 medium 40 · 이상 small 36 |
| Popover | 폭 320 ~ 480 · 최대 높이 600 · radius-r5 · shadow-s3 · 트리거와 8 · 머리 제목 t7 + 닫기 · d3 enter 로 0.95 배에서 커진다 |
| 쌓임 | specs/z-index.md — 시트 · 대화상자 L2(z-modal 100 · z-modal-content 101) · Popover L3(z-floating 200) · Alert Dialog L5(z-alert 300 · z-alert-content 301) |
쓰는 규칙
- 입력 폼은 바깥 누르기 · 끌어내리기로 닫지 않는다 — 닫기 버튼 · 취소 ·
Esc· 뒤로 가기로 닫고, 바뀐 값이 있으면 "작성한 내용이 사라져요" 를 묻는다(Field). - 닫기 버튼과 바닥 취소를 함께 두지 않는다 — 대화상자의 입력 폼은 바닥 [취소] [저장], 시트의 입력 폼은 위 닫기 + 바닥 [저장], 조회 · 안내 · 고르기는 위 닫기.
- 확인창은 닫기 버튼이 없고 바깥 누르기를 무시한다.
Esc는 취소. 확인창 안에 입력칸을 두지 않는다. - 버튼 글은 동작 이름("삭제" · "저장" · "그룹 삭제") — "확인" 으로 뭉뚱그리지 않는다. 예외는 고를 것이 없는 결과 알림(Alert Dialog
single)의 "확인" 하나다(2026-10-22 사용자 결정 5B). - 확인창은 대상을 이름으로 짚는다 — 제목이든 설명이든, 같은 동작은 어디서 불러도 같은 글(6B).
Accessibility 체크리스트
- 모달(시트 · 대화상자 · 확인창) —
role="dialog"· 확인창role="alertdialog",aria-modal="true", 제목aria-labelledby· 설명aria-describedby, 열면 표면으로 초점 · 닫으면 연 자리로, 열린 동안 초점을 가두고 뒤 화면을 숨기고 스크롤을 잠근다 - Popover —
role="dialog"(aria-modal 없음), 초점은 안으로 · 가두지 않음 · Tab 으로 나가면 닫힘, 트리거aria-haspopup="dialog"·aria-expanded - 닫기 버튼 이름 "닫기", 시트 닫기 누르는 영역 44
- 대화상자 높이 80% 상한 — 머리 · 바닥이 화면 밖으로 나가지 않는다
알림 메시지 — Snackbar · Callout · Page Banner · Result Section
2026-10-02 SEED Snackbar · Callout · Page Banner · Result Section 구조로 다시 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/8t85WkZ3HLhMu8KibW3Vk1). 수치 원본은
specs/components/snackbar.yaml·callout.yaml·page-banner.yaml·result-section.yaml, 쓰는 규칙은 각 스펙 md 다. 옛 Toast 절(흰 카드 · 위 오른쪽 · 3장 쌓기 · 오류 8초)과 Sonner(v72) · Banner(v73) 절은 걷었다. 반전 짝 역할 셋(v115 —fg-brand-inverted·fg-positive-inverted·fg-critical-inverted)을 이 묶음에서 들였다.
나누기
무엇으로 알리나 — 상황 → 고를 것 표와 다섯 부품(Snackbar · Callout · Page Banner · Result Section · Alert Dialog) 견주기 표는 specs/components/snackbar.md 의 "무엇으로 알리나" 한 벌이다(2026-10-22 사용자 결정 3B — 알리고 기다리는 것 정리 페이지 https://claude.ai/artifact/NuEPiLRH2fJidXdKzcDsCX). 나누는 법은 일로 나눈다 — 방금 한 일의 결과 · 가벼운 실패는 Snackbar, 그 자리의 안내 · 오류는 Callout, 페이지 전체의 상태는 Page Banner, 비어 있음 · 실패 · 완료는 Result Section, 되돌릴 수 없는 결정 · 꼭 알아야 할 일은 Alert Dialog.
오류는 자리에서 알린다 — 모든 실패를 한곳에서 토스트로 띄우지 않는다(서버가 보낸 글 · 영어 · 코드를 그대로 보이지 않는다). 시트 · 대화상자에서 한 일은 창이 열린 채 봐야 하면 그 안 Callout, 창을 닫으며 끝나면 닫힌 뒤 토스트, 칸 하나가 틀리면 칸 아래다(2B).
모양
| Snackbar | Callout | Page Banner | Result Section | |
|---|---|---|---|---|
| 자리 | 화면 아래 가운데 · 탭 바 · 플로팅 버튼 위 8 · 최대 464 | 본문 안 · 콘텐츠 폭 | 페이지 맨 위 · 화면 폭 | 놓인 자리 가운데 |
| 면 | bg-neutral-inverted(다크는 밝은 띠) · 모서리 8 · 그림자 없음 | bg-*-weak · 모서리 10 | bg-*-weak · bg-*-solid · 모서리 0 | 없음 |
| 크기 · 여백 | 최소 44 · 10 + 6(글은 16) | 최소 50 · 14 | 최소 40 · 10 / 24 | 좌우 48 · 위아래 16 |
| 글 | 14 / 19 | 14 / 19 · 제목 700 · 한 문단 | 14 / 19 · 제목 700 · 본문 500 | 제목 22 / 30 · 16 / 22 · 설명 muted |
| 아이콘 | 24 — 성공 · 실패만(fg-*-inverted) | 16 · 톤 색 | 16 · 톤 색 | 40 |
| 버튼 | 액션 하나 · fg-brand-inverted 14 · 700 | 링크 · 전체 누르기 · 닫기 | 글 버튼 하나 13 · 700 · 닫기 | neutralWeak 40 + 글 버튼 |
| 시간 · 쌓임 | 4초 · 액션 6초 · 머무는 동안 멈춤 · 한 번에 하나(새 띠는 바로 바꾸고, 액션이 달린 띠만 끝날 때까지 지킨다 — 1B) · z L6(400) | 늘 보임 | 늘 보임 · 한 화면 하나 | 늘 보임 |
톤은 다섯(neutral · informative · positive · warning · critical) — 옅은 바탕은 bg-*-weak + fg-*-contrast, 짙은 바탕은 bg-*-solid + 흰 글(static-white). 아이콘은 lucide 선 아이콘(v106).
쓰는 규칙
- 글 — 해요체 문장에 마침표(스낵바도 — Writing v106). 무엇이 됐는지 먼저("거래를 저장했어요."), 오류는 할 수 있는 일까지. "실패" 로 끝나는 말 · 서버가 보낸 글 · 영어 · 코드를 쓰지 않는다. 액션은 동작 이름("되돌리기").
- 닫기 — Callout · Page Banner 는 한 번 보면 되는 안내에만 닫기를 두고, 닫은 것을 기억한다. 경고 · 오류는 닫지 못한다.
- 실패는 비어 있음과 다르게 — 불러오기 실패를 "내역이 없어요" 로 보이지 않는다. Result Section 의 실패 + "다시 시도".
접근성
- Snackbar: 자리
aria-live="polite"· 띠role="status"+aria-atomic, 초점을 옮기지 않는다. 보조 기술용 닫기는 키보드 초점이 오면 보인다. - 나중에 나타나는 경고 · 위험(Callout · Page Banner)은
role="alert". Result Section 은 결과로 바뀌면role="status", 제목은 제목 태그.
메뉴 · 메뉴 시트 · 도움말 말풍선 · 툴팁
2026-10-02 SEED Menu · Menu Sheet · Help Bubble · Help Bubble Tooltip 구조로 다시 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/QoxJ7ZmQCedRWfPQrDvFgA, 여덟 다 SEED 쪽). 수치 원본은
specs/components/menu.yaml·menu-sheet.yaml·help-bubble.yaml(툴팁도 이 파일), 쓰는 규칙은 각 스펙 md 다. 옛 Tooltip 절(반전 · 모서리 4 · 240 · hover 500ms)과 Dropdown 절(테두리 1px · 모서리 8 · 줄 36 · menu · select · multi-select · combobox 변형)은 걷었다 — 값 고르기는 Select · Input Button 절, 메뉴는 여기. Menubar · Hover Card · Context Menu 는 세 제품 모두 쓰는 곳이 없어 걷었다.
나누기
| 이런 일 | 1280 미만 | 1280 이상 |
|---|---|---|
| 줄 · 화면의 동작(수정 · 복사 · 삭제 · 내보내기) | Menu Sheet | Menu |
| 값 고르기(테마 · 정렬 · 보기) | 테마는 List 라디오 줄, 정렬 · 보기는 Segmented Control · Select — 메뉴가 아니다(고르는 표는 specs/components/select.md 의 "고르는 컴포넌트 고르기" 한 곳 — 2026-10-22 1B) | 같다 |
| 아이콘 버튼 · 줄인 글의 짧은 설명 | — (툴팁은 터치에서 안 열린다 — 이름은 aria-label) | Tooltip |
| 몰라도 일은 할 수 있는 설명(규정 · 계산 방법) | Help Bubble(ⓘ 를 눌러서) | Help Bubble |
| 버튼 · 고르는 칸이 있는 내용 | Bottom Sheet | Popover — 저장해야 남는 입력은 칸 하나라도 Dialog(위 "시트 · 대화상자 · 확인창 · 팝오버" 의 나누기) |
모양
| Menu | Menu Sheet | Help Bubble · Tooltip | |
|---|---|---|---|
| 표면 | bg-layer-floating · 모서리 20 · shadow-s3 · 폭 200 · 위아래 8 | bg-layer-floating · 위 모서리 20 · 최대 480 · 손잡이 늘 · 딤 | bg-neutral-inverted · 모서리 12 · 최대 280 · 화살표 12×8 · 그림자 없음 |
| 줄 · 글 | 39(설명 있으면 57) · t4 14 · 아이콘 18 · 좌우 16 | 52 · t5 16 · 아이콘 22 · 묶음 bg-neutral-weak 모서리 16 | t3 13(제목 700) · 위아래 10 좌우 12 |
| 누름 · 호버 | 좌우 8 들인 알약 bg-layer-floating-pressed · 내용만 축소 | 줄 bg-neutral-weak-pressed · 내용만 축소 — 설명은 fg-neutral-muted · 위험 글자는 fg-critical-contrast 로(누름 바탕 위 4.5:1) | 닫기 버튼만 축소 |
| 키보드 | 알약 자리 2px 링(호버와 따로) · ↑↓ 순환 · 한 글자 찾기 | 줄 안쪽 링 · Tab | 닫기 버튼 안쪽 링(말풍선 글자색) |
| 묶음 · 위험 | 묶음 사이에만 선 · 위험은 맨 아래 묶음 fg-critical | 묶음 사이는 간격 · 위험은 맨 아래 묶음 | — |
| z-index | L3 z-floating 200 | L2 z-modal 100 / z-modal-content 101 | L4 z-tooltip 210 |
쓰는 규칙
- 메뉴는 실행만 — 누르면 바로 실행하고 닫힌다. 고른 표시(체크 · 라디오) · 단축키 · 하위 메뉴가 없다.
- 목록 줄에는 ⋮ 를 두지 않는다 — 좁은 목록 줄(List 줄 — 한두 줄 글 + 타일 · 값)은 누르면 한 단계 들어가고(상세 · 수정), 동작은 들어간 화면에 둔다. 하나(삭제)면 바닥 왼쪽 [삭제]
ghost+critical(Button 모달 footer 꼴 — 1280 미만 시트도 같다), 여럿이면 머리 오른쪽 ⋮ 하나("{항목 이름} 더보기") → Menu(1280 미만 Menu Sheet). 수정 · 삭제 아이콘을 줄마다 늘 늘어놓지 않는다(2026-10-25 사용자 결정 — 2026-10-02 의 "데스크톱 줄의 동작은 줄 끝 ⋮ + Menu" 를 고쳤다). - 줄에 ⋮ 를 두는 자리는 콘텐츠가 높은 카드 머리뿐 — 사진 · 여러 줄 · 버튼이 든 카드 하나가 항목 하나일 때. 데스크톱 데이터 표의 줄 끝 ⋮ 는 이 규칙 밖이다 — 그루 이음 관리 화면 차례에 다시 보고, 그때까지 Table 스펙의 지금 문장을 따른다.
- 폰 스와이프는 지름길 — 같은 동작은 줄을 눌러 들어간 화면에 다 둔다(키보드 · 스크린리더의 길).
- 비모달 Menu — 뒤 화면을 숨기지 않는다.
Tab· 바깥 누르기로 나가면 닫히고, 고르면 실행하고 닫혀 초점은 트리거로. - 툴팁은 마우스(200 / 100ms) · 키보드(바로)의 보조 — 이름은
aria-label, 막힌 이유는 가까운 글, 네이티브title은 쓰지 않는다. 폰에서도 읽어야 하는 설명은 Help Bubble. - 글 — 메뉴 줄은 동사로 짧게(2 ~ 6자), 툴팁 · 말풍선은 해요체 · 문장이면 마침표.
접근성
- Menu: 트리거
aria-haspopup="menu"·aria-expanded,role="menu"·menuitem·group. 키보드 위치는 링으로(바탕색만으로 알리지 않는다). - Menu Sheet:
role="dialog"+aria-modal, 줄은<button>. 보이지 않는 "닫기" 는 키보드 초점이 오면 보인다. - Help Bubble:
role="dialog"(비모달) + 제목aria-labelledby. Tooltip:role="tooltip"+ 트리거aria-describedby, WCAG 1.4.13(말풍선 위로 옮겨도 남는다 ·Esc).
Tabs · Segmented Control
수치 · 규칙의 원본은 specs/components/tabs.md · tabs.yaml · chip-tabs.yaml 과 segmented-control.md · segmented-control.yaml 이다 — 2026-10-02 SEED Tabs · Segmented Control 구조로 새로 정했다(옛 variant 넷 · 수동 활성화를 걷었다). 이 절은 토큰과 닿는 자리만 모은다.
나누기
| 자리 | 컴포넌트 |
|---|---|
| 다른 구역 · 페이지로 옮긴다(1차, 화면 · 구역 맨 위) | Tabs — Line |
| 1차 탭 안에서 다시 나눈다(2차) | Tabs — Chip Tabs(필터 바가 같은 화면에 있으면 Line) |
| 같은 내용 2 ~ 4가지 거르기 · 정렬 · 보기(그 내용 바로 위, 한 화면 하나) | Segmented Control |
| 2 ~ 4개 짧은 폼 값 · 목록 조건 | Chip(하나 고르기 · 필터 바) |
Line
| 요소 | 값 |
|---|---|
| 크기 | small 40 · 글 t4 14(기본) · medium 44 · 글 t5 16. 탭 위아래 · 좌우 10, 글은 아래로 붙인다. 글은 고르든 안 고르든 700 |
| 색 | 안 고름 fg-neutral-subtle, 고름 fg-neutral + 아래 2px fg-neutral 막대(motion-duration-d4 · motion-ease-easing 로 미끄러진다). 브랜드 색 · 굵기 변화 없음 — Desk · HR 이 같다 |
| 목록 | bg-layer-default + 바닥 안쪽 1px stroke-neutral-subtle |
| 폭 | Fill — 5개 이하 · 짧은 글, 칸을 나누고 막대를 좌우 16 들인다. Hug — 6개 이상 · 긴 글 · 넓은 데스크톱 자리, 목록 좌우 16 · 넘치면 가로 스크롤(고른 탭으로 16 여유를 두고 스크롤) |
| 누름 · 포커스 · 비활성 | 탭 2px 거리 축소만(색 · 호버 모양 없음) · 탭 안쪽 링 2px · 글 fg-disabled |
| 알림 점 | Notification Badge small — 6 · 브랜드 글자색(브랜드 파일의 fg-brand, 다크에서 밝은 짝), 글 끝 2 · 줄 상자 위 — 새 소식이 있는 탭 하나에만 |
Chip Tabs
칩 하나는 Chip(chip.yaml)의 Solid · Outline Strong 그대로다 — medium 36(기본) · large 40, 고르면 bg-neutral-inverted · fg-neutral-inverted. 목록은 좌우 spacing-global-gutter · 위아래 8 · 칩 사이 spacing-between-chips, 한 줄 가로 스크롤. 화면 전체 내용을 바꾸면 Solid, 일부면 Outline.
Segmented Control
| 요소 | 값 |
|---|---|
| 크기 | 트랙 안쪽 4 + 칸 34 = 42, 글 t5 16 · 700, 칸 좌우 12 — 칸이 트랙 폭을 똑같이 나눈다(최소 폭 없음 — 폰에서도 4개) |
| 색 | 트랙 bg-neutral-weak-alpha(투명 — 회색 바닥 위에서도 보인다, v120), 안 고른 글 fg-neutral-subtle, 고른 칸은 흰 알약 bg-layer-default + 안쪽 짙은 1px stroke-neutral-contrast 위 fg-neutral(motion-duration-d4 로 미끄러진다 — SEED 의 옅은 1px 은 트랙과 1.14:1 이라 바꿨다) |
| 누름 · 호버 | 안 고름 bg-neutral-weak-pressed + 1px stroke-neutral-weak(글 fg-neutral-muted) · 고름 bg-layer-default-pressed + 짙은 1px 그대로, 칸 안의 글만 2px 거리 축소 |
| 비활성 | 글 fg-disabled, 고른 채 막히면 칸에 bg-disabled + 1px stroke-neutral-solid(흐림 없음 — v106) |
쓰는 규칙
- 화살표로 옮기면 바로 고른다(자동) — 바로 저장되거나 되돌리기 어려운 값은 탭 · Segmented 에 두지 않는다(폼 값은 Chip · Select).
- 탭 내용은 바로 바꾸고 탭마다 상태(스크롤 · 입력)를 남긴다. 폰의 1차 탭만 밀어 넘기고, 웹은 1차 탭을 주소에 남긴다.
- 탭 · Segmented 글에 개수를 붙이지 않는다 — 새 소식은 한 탭에 알림 점.
Accessibility 체크리스트
- Tabs —
tablist(보이는 제목 또는aria-label) ·tab(aria-selected·aria-controls) ·tabpanel(aria-labelledby), 고른 탭만tabindex="0",←→·Home·End로 옮기며 고른다(끝에서 처음으로, 막힌 탭은 건너뛴다) - Segmented Control —
radiogroup(aria-label) + 라디오, 화살표로 옮기며 고른다 - 알림 점은 보조 기술에 "새 소식" 을 덧붙인다
- 키보드 포커스 링 — Line 은 탭 안쪽, Chip Tabs · Segmented 는 바깥
- 누르는 높이 — Line small 40 · Segmented 34 는 AAA(44)에 못 미친다(AA ✓)
Switch / Checkbox / Radio (control 묶음)
binary on/off 상태 또는 group 선택을 표현하는 form control 3종. 공통 a11y 베이스 + 시맨틱 차이.
의미 차이
| Component | 의미 | 변경 시점 |
|---|---|---|
| Switch | 즉시 적용되는 토글 (on/off) | 누르는 순간 적용 (e.g. 알림 켜기/끄기) |
| Checkbox | 다중 선택 또는 단일 confirm | form submit 시점 또는 즉시 적용 |
| Radio | 그룹 내 단일 선택 | form submit 또는 즉시 |
선택 기준: 즉시 적용 + on/off → Switch, 다중 선택 + form → Checkbox, 단일 선택 + group → Radio. UI 혼동 회피를 위해 의미별 명확히 분기. Switch 는 누르는 순간 적용될 때만 쓴다 — 저장 · 실행을 눌러야 적용되는 켜고 끄기는 Checkbox 다(2026-09-30 사용자 결정 — SEED 와 같다). 누르면 화면이 바로 바뀌는 것(일정의 "종일")은 값이 저장 때 들어가더라도 Switch.
Spec 공통 (신규 토큰 없음)
세 컨트롤 모두 2026-09-30 SEED 구조로 바뀌었다(아래 Switch · Checkbox · Radio, specs/components/switch.md · checkbox.md · radio-group.md). 색 규칙은 셋이 같다(사용자 결정).
| 요소 | 값 |
|---|---|
| 선택 · 켜짐 채움 | bg-neutral-inverted(짙은 회색)가 기본. 브랜드 채움은 tone="brand" 일 때만 — 서비스 핵심 흐름 |
| 선택 · 켜짐 표시(체크 · 점 · 엄지) | fg-neutral-inverted. tone="brand" 면 static-white |
| 선택 안 됨 · 꺼짐 | stroke-neutral-solid(표면과 3:1 이상, v109) — Checkbox · Radio 는 1px 테두리, Switch 는 트랙 채움 |
| disabled | 전용 색(v106 — State 절), 불투명도로 흐리게 하지 않는다. 선택 · 켜진 채 막히면 모양 그대로 회색 — Checkbox · Radio 는 bg-disabled 채움 + fg-disabled 표시, Switch 는 fg-disabled 트랙 + bg-disabled 엄지. cursor:not-allowed |
| hover | Checkbox · Radio 는 누름 색. Switch 는 색이 바뀌지 않는다 — 켜짐 색이 상태를 뜻해서(v104) |
| pressed | 칸 · 동그라미 · 스위치만 세로 2px 거리 축소(v104) |
| focus | 키보드 포커스에만 링 2px · 띄움 2px(v106) |
Switch
상세 spec(Anatomy / Sizes / States / Motion / Accessibility / Do-Don't)은
specs/components/switch.md가 단일 SoT. 코드(recipes/shadcn/components/ui/switch.tsx) · 예제(recipes/shadcn/examples/switch-examples.mjs) · preview 4 source 동기.
- 구조: 스위치(Switchmark — 트랙 + 엄지) · 스위치 + 라벨(Switch) — SEED Switch(2026-09-30).
- 크기(이름은 트랙 높이):
16트랙 26 × 16 · 엄지 12 · 라벨 13 /2438 × 24 · 20 · 14(기본) /3252 × 32 · 26 · 16. 트랙 · 엄지 모서리radius-full. - 끄면 엄지가 0.8 로 작아진다 — 색 말고도 자리 · 크기로 켬 · 끔이 갈린다. 엄지에 그림자는 없다.
- 톤:
neutral(짙은 회색, 기본) ·brand. - 모션: 엄지의 이동 · 크기
motion-duration-d3(150ms), 색은 20ms 뒤에motion-duration-d1(50ms) — 둘 다motion-ease-easing. 누르면 스위치만 세로 2px 거리 축소(색은 그대로). - 누르는 순간 적용되는 설정에만 쓴다 — 저장해야 적용되는 값은 Checkbox.
- "라벨 왼쪽 · 스위치 오른쪽" 설정 줄(제목 · 설명 · 아이콘)은 List 의 스위치 줄(
ListSwitchItem— 아래 List)이다. 그 줄에는 스위치 32 만(Switchmark) 끼우고 줄 전체가 누르는 영역이다 — 줄을 누르면 콘텐츠가 함께 줄고 스위치는 따로 줄지 않는다. - 터치 타겟은 스위치 단독으론 작음(높이 16 · 24 · 32). 반드시 라벨까지 묶어 44 확보(WCAG 2.5.5 AAA) — 설정 줄에 스위치만 넣으면 줄 전체.
Checkbox
상세 spec(Anatomy / Sizes / States / Motion / Accessibility / Do-Don't)은
specs/components/checkbox.md가 단일 SoT. 코드(recipes/shadcn/components/ui/checkbox.tsx) · 예제(recipes/shadcn/examples/checkbox-examples.mjs) · preview 4 source 동기.
- 구조: 칸(Checkmark) · 칸 + 라벨(Checkbox) · 묶음(Checkbox Group) — SEED Checkbox(2026-09-30).
- 크기:
medium칸 20 · 라벨 14 · 줄 32(기본) /large24 · 16 · 36. 모서리radius-r1(4px). - 모양:
square(칸 + 체크, 기본) ·ghost(칸 없이 체크만 — 필수가 아니고 셋 이하). 톤:neutral(짙은 회색, 기본) ·brand. - 일부 선택(indeterminate): 가로줄 — 부모 · 자식 묶음에서 자식을 일부만 골랐을 때.
- 터치 타겟은 칸 단독으론 작음(20 · 24). 반드시 라벨까지 묶어 44 확보(WCAG 2.5.5 AAA) — 목록 행에 칸만 넣으면 행 전체.
- 오류는 칸을 바꾸지 않는다 — 묶음 아래 글로 알린다.
Radio
상세 spec(Anatomy / Sizes / States / Motion / Accessibility / Do-Don't)은
specs/components/radio-group.md가 단일 SoT. 코드(recipes/shadcn/components/ui/radio-group.tsx) · 예제(recipes/shadcn/examples/radio-group-examples.mjs) · preview 4 source 동기.
- 구조: 동그라미(Radiomark) · 동그라미 + 라벨(Radio) · 묶음(Radio Group) — SEED Radio(2026-09-30).
- 크기:
medium동그라미 20 · 점 8 · 라벨 14 · 줄 32(기본) /large24 · 10 · 16 · 36. 모서리radius-full. - 선택: 테두리 없이 채운 원 + 가운데 점. 톤:
neutral(짙은 회색, 기본) ·brand. - 묶음은 세로로만 쌓는다(줄 사이 12 — 줄마다 누르는 영역 44 를 온전히 받게, SEED 는 4) — 짧은 선택지를 한 줄에서 고르게 하려면 Segmented · Chip.
- 설명 · 딸린 입력이 붙는 선택지는 Radio 가 아니라 Select Box(아래 Select Box).
- 오류는 동그라미를 바꾸지 않는다 — 묶음 아래 글로 알린다.
Layout
- label 위치: control 우측 (LTR) — control과 label 간
sm(8px) 간격 - 그룹 spacing:
- vertical group: 항목 간
md(12px) ~lg(16px) — Checkbox · Radio 묶음은 줄 최소 높이 32 · 36 에 줄 사이 12(specs/components/checkbox.yaml·radio-group.yaml— 줄마다 누르는 영역 44 를 온전히 받는다, 사용자 결정 2026-09-30. SEED 는 4) - horizontal group: 항목 간
lg(16px) — Radio 는 가로로 놓지 않는다(2026-09-30)
- vertical group: 항목 간
- group label (group 제목): control 위
caption+xs간격
Touch target (WCAG 2.5.5)
- control 자체는 작음(Radio 동그라미 · Checkbox 칸 20 · 24, Switch 트랙 높이 16 · 24 · 32) — 반드시 label까지 포함한 hit area가 44×44px 이상 확보 필수
- label 클릭으로도 toggle/select 가능 (
<label for="...">또는 control wrap)
Accessibility
- HTML:
<input type="checkbox|radio">+<label for="...">사용 — native a11y 자동- Switch는 HTML native 없음 →
<input type="checkbox" role="switch">또는role="switch"+aria-checked. 스위치만 쓰는 설정 줄은 줄의 제목이 스위치의 이름이 되게<label>로 감싸거나aria-labelledby로 잇는다
- Switch는 HTML native 없음 →
- focus ring: control 외곽 + label 영역 모두 focus indicator 표시 (
border-focus2px outline) - aria 상태:
- Checkbox:
aria-checked="true|false|mixed"(mixed = indeterminate) - Radio: group은
role="radiogroup"+aria-labelledby="group-title" - Switch:
role="switch"+aria-checked(또는 native checkbox +role="switch")
- Checkbox:
- 키보드:
- Checkbox/Switch:
Space로 toggle (Switch 는Enter도) - Radio: arrow keys (
↑/↓또는←/→)로 group 내 이동, 선택 즉시 - Tab으로 group 진입 → 첫 번째 또는 현재 선택값으로 focus
- Checkbox/Switch:
- disabled 상태: control + label 모두 disabled 표시 + 1.4.3 incidental
- error 상태 (form validation 실패): Checkbox · Radio 는 칸 · 동그라미를 바꾸지 않고 묶음 아래 글로(2026-09-30). Switch 에는 오류 상태가 없다 — 누르는 순간 적용되므로 검증할 값이 없고, 저장에 실패하면 스위치를 되돌리고 무엇이 안 됐는지 알린다
List
상세 spec(Anatomy / 줄의 종류 / 상태 / 모션 / Accessibility / Do-Don't)은
specs/components/list.md가 단일 SoT, 수치는list.yaml·list-header.yaml. 코드(recipes/shadcn/components/ui/list.tsx) · 예제(recipes/shadcn/examples/list-examples.mjs) · preview 4 source 동기.
- 구조: 목록(List) · 한 줄(List Item) · 목록 제목(List Header) · 줄 사이 선(ListDivider) — SEED List(2026-10-01). 설정 · 메뉴 · 선택 · 키-값 줄과 거래 · 할 일 · 알림 같은 내용 줄을 모두 List 로 그린다. RadioList 는 걷었다 — 하나 고르기는 오른쪽 라디오 줄(
ListRadioItem). - 한 줄: 위아래
spacing-x3(12) · 좌우spacing-global-gutter(24) · 제목t516 · 400fg-neutral· 설명t313fg-neutral-subtle(제목 아래 2) — 한 줄 46 · 두 줄 66. - 앞: 설정 · 메뉴 줄은 아이콘 22(
fg-neutral), 색이 뜻을 가진 내용 줄은 타일 40(모서리radius-r312 ·chart-{색}-weak바탕 · 아이콘 20 — 아이콘이 없으면 태그 아이콘, 이체 줄은 회색). 은행 · 카드 같은 물건 줄은 로고 타일 40(Logo Tile), 카드 혜택 줄은 카드 그림 56(Image Frame). 체크 · 라디오는 24, 스위치는 32. - 뒤: 값 글자(
t5·fg-neutral-subtle) · 오른쪽 화살표 18(화면을 옮기는 줄에만) · 컨트롤 · 작은 버튼. - 누름 · 호버(웹): 바탕 층이 좌우 6 들어와 모서리 10 의
bg-layer-default-pressed가 되고, 콘텐츠 층만 2px 거리로 준다(v104). 끼운 컨트롤은 따로 줄지 않는다. 포커스 링은 줄 안쪽 2px. - 강조: 바탕만 옅은 브랜드 색(브랜드 파일의 brand-weak 역할 색 — 누름 · 호버는 한 단계 짙은 짝, 그동안 설명 · 값 글자는
fg-neutral-muted로 4.5:1 을 지킨다). - 줄 사이 선은 기본 없음 — 필요할 때만
ListDivider(1pxstroke-neutral-subtle, 줄 폭 또는 좌우 24 들임). - 목록 제목:
t414 · 위아래 8 · 좌우 24 —mediumWeak(500 ·fg-neutral-subtle, 기본) ·boldSolid(700 ·fg-neutral). - 하위 줄(2026-10-10): 부모 · 하위 두 단계에서 줄은 편집을 열고 하위만 접는 목록(카테고리) — 부모 줄 앞 꺾쇠 단추 44(이름 "{카테고리} 하위 카테고리" +
aria-expanded· 펼치면 90° · 300ms) · 하위 줄은 부모 제목 자리 104 · 하위가 없는 줄도 꺾쇠 자리를 비워 부모 타일이 한 세로줄(52)에 선다(17B). 여러 단계에서 고르는 나무는 Tree View. - 목록은 흰 바탕(
bg-layer-default) · 시트(bg-layer-floating) 위에 둔다 — 회색 바탕(bg-layer-basement) 위에서는 누름 바탕이 보이지 않는다(카드에 담는다).
Select Box
상세 spec(Anatomy / 컨트롤 / 배치 / 상태 / 펼침 / 모션 / Accessibility / Do-Don't)은
specs/components/select-box.md가 단일 SoT, 수치는select-box.yaml. 코드(recipes/shadcn/components/ui/select-box.tsx) · 예제(recipes/shadcn/examples/select-box-examples.mjs) · preview 4 source 동기.
- 구조: 하나 고르기(Radio Select Box) · 여럿 고르기(Check Select Box) · 묶음(Select Box Group) — SEED Select Box(2026-10-01). 설명 · 아이콘 · 딸린 입력이 붙는 선택지 2 ~ 6개를 견줘 고르고, 저장 · 다음 같은 버튼으로 반영한다. Tile 은 걷었다.
- 상자: 모서리
radius-r3(12) · 안쪽 1pxstroke-neutral-weak. 고르면 안쪽에 2pxstroke-neutral-contrast(v113)를 덧그린다 — 내용이 밀리지 않고, 바탕은 그대로다(브랜드 색 없음). - 글자: 제목
t516 · 500fg-neutral· 설명t313fg-neutral-muted(두 줄까지). 앞 아이콘 22(fg-neutral). - 컨트롤은 오른쪽 — 라디오 20(neutral) · 칸 없는 체크(Checkbox Ghost) · 없음(테두리만, 좁은 3열 같은 자리). 컨트롤은 따로 줄지 않고 자기 포커스 링도 그리지 않는다.
- 배치: 1열은 가로형(위아래 16 · 왼쪽 20 · 오른쪽 16, 세로 가운데), 2 ~ 3열은 세로형(위아래 20 · 좌우 16, 앞이 위 · 컨트롤은 위 오른쪽). 묶음 줄 사이
spacing-component-default· 열 사이 12, 2열 이상이면 모든 상자가 가장 긴 상자의 높이다. 가장 작은 상자 54. - 누름 · 호버(웹): 상자 바탕이
bg-layer-default-pressed가 되고 누르는 자리(콘텐츠 + 컨트롤)만 2px 거리로 준다(v104). 키보드 포커스 링은 상자 바깥 2px · 띄움 2px. - 펼침: 고른 상자 아래로 딸린 입력 · 안내가 열린다(안쪽 좌우 20 · 아래 16, 높이 400ms · 투명도 300ms). 닫히면 보이지 않고 Tab 도 닿지 않는다.
- 누르는 순간 바뀌는 고르기(테마 같은)는 List 의 라디오 줄, 누르면 바로 무언가를 하는 자리는 버튼이다.
- 권한을 주는 여럿 고르기(HR 사용자 역할)도 상자로 고르고 "저장" 한 번으로 반영한다 — 폰 · 데스크톱 같은 모양(2026-10-15 마무리 10A, 위 "마무리" 절).
Avatar · Avatar Stack
2026-10-03 SEED Avatar · Avatar Stack 구조로 다시 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/4ySVacsdnG4fgraR1HRK3G, 5C · 6B). 수치 원본은
specs/components/avatar.yaml·avatar-stack.yaml, 쓰는 규칙은avatar.md다. 옛 Avatar v58 절(24 · 32 · 40 · 56 · 사각 변형 · 최대 3 + "+N more" · 호버 축소 · 상태 점)은 걷었다 — 옛 스펙은specs/components/avatar.history/v-pre-seed-display.*. 머리말의avatar대비 쌍(chart-blue× 흰 글자)은 라이트 이니셜 하나를 잰다.
| Avatar | Avatar Stack | |
|---|---|---|
| 크기 | 20 · 24 · 36 · 42 · 48 · 56 · 64 · 80 · 96 · 108 — 자리마다 대표 크기(한 줄 목록 36 · 두 줄 목록 42 · 줄 안 묶음 24 · Desk 계정 머리 80 · HR 큰 사진 96 · 프로필 수정 108) | 같은 10단계 — 묶음이 정하고 안의 아바타가 모두 따른다 |
| 모양 | 원 하나 · 1px 안쪽 stroke-neutral-overlay(투명 — v118, 모든 크기) | 지름 1/4 겹침(−5 ~ −27) · 놓인 바탕색 링 1 ~ 5(bg-layer-default, 시트 안은 bg-layer-floating) · 뒤가 위 |
| 사진이 없을 때 | 이니셜 + 이름 색 — 차트 10색(v110) 바탕, 글자 fg-neutral-inverted 700(지름의 40%, 가장 작아도 10) | 앞 4명 + "+N" 원(같은 크기 · bg-neutral-weak + fg-neutral-muted 700) |
- 이니셜 = 표시 이름의 첫 글자 하나(로마자는 대문자 — "Kim Minsu" → "K"). 이름 색 = 표시 이름의 유니코드 코드 포인트 합 % 10 → blue · green · orange · violet · pink · indigo · red · yellow · brown · gray(v110 순서) — 웹 · 앱이 같다("김민수" → blue · "이서연" → brown · "Kim Minsu" → indigo). 대비 라이트 4.55 ~ 5.50 · 다크 6.07 ~ 7.70:1 — 다크에서 흰 글자는 2.4:1 이라 쓰지 않는다.
- 사람만 아바타다 — 은행 · 증권 · 카드 같은 물건은 Logo Tile, 카테고리는 List 의 타일이다("이미지" 절). 주식 타일은 증권 화면 차례에 정한다.
- 이름 옆 아바타는 장식(이름을 한 번만 읽는다), 혼자면 이름을 가진다. 상태(안 낸 사람)는 흐리게 하지 않고 배지 · 글로.
날짜 · 시각 고르기 — Date Picker · Time Picker · Wheel Picker
2026-10-03 SEED 구조로 새로 정했다(옛 Calendar v61 · Date Range Picker v72 · Time Picker v72 를 대신). 수치 원본은
specs/components/date-picker.yaml·time-picker.yaml·wheel-picker.yaml, 쓰는 규칙은 같은 이름의.md. 옛 Calendar 스펙은specs/components/calendar.history/v-pre-seed-date.*.
날짜 · 시각은 치지 않고 고른다 — 칸은 Input Button 이고, 누르면 1280 미만은 아래 시트 · 이상은 칸 아래 팝오버가 열리며 "완료" 로 넣는다(고르는 동안 칸 값은 그대로, 닫으면 버림).
| 이런 값 | 고르는 것 |
|---|---|
| 날짜 하나 | Date Picker — 한 달, 늘 6주 |
| 기간 | Date Picker 기간 — 칸 하나("9월 28일~10월 6일"), 시트는 이어지는 달 · 팝오버는 두 달, 위에 빠른 기간 칩 |
| 여러 날 | Date Picker 여러 날 — 따로 그린 원 |
| 시각 | Time Picker — 오전·오후 → 시 → 분, 분 간격 기본 5 |
| 날짜 + 시각 | 날짜 칸 + 시각 칸 나란히 |
| 달만(예산 · 홈 · 카드 실적) | Wheel Picker 연 · 월 + "완료" |
| 1 ~ 31(매월 N일 · 결제일) | Select |
| Date Picker | Time Picker · Wheel Picker | |
|---|---|---|
| 크기 | 칸 48(폭 ÷ 7) · 원 42 · 머리 · 요일 48 · 늘 6주 · 팝오버 336 · 두 달 696 | 항목 44 × 5 = 220 · 연 · 월 휠 7칸 · small 36 |
| 글자 | 숫자 t5 500 fg-neutral-muted · 요일 t4 500 fg-neutral-subtle · 제목 t5 700 | 항목 26 / 35 · 500 — 고른 것 fg-neutral · 둘레 fg-disabled |
| 상태 | 오늘 옅은 원 bg-neutral-weak + 숫자 700 · 고름 bg-neutral-inverted · 기간 띠 bg-neutral-weak · 앞뒤 달 fg-disabled(누르지 못함) · 막힘 fg-disabled + 취소선 · 읽기 전용 stroke-neutral-solid | 띠 bg-neutral-weak 모서리 8 · 좌우 16 들임 · 안개 min(40%, 3칸) |
| 키보드 | WAI-ARIA Grid — ←→ 하루 · ↑↓ 한 주 · PageUp/Down 한 달 · Shift+Page 한 해 | 칼럼마다 Tab · ↑↓ · Home · End |
| 칸 표기 | 올해 "10월 15일 (목)" · 다른 해 "2027년 1월 3일 (일)" · 기간 물결표 | "오후 3:00" |
빠른 기간은 한 벌이다 — 이번 주(일 ~ 토) · 이번 달(1일 ~ 말일) · 지난 달 · 최근 7일 · 30일 · 최근 3개월 · 6개월 · 1년(이번 달을 넣은 달들) · 올해(1월 1일 ~ 12월 31일). 화면은 이 안에서 고른다.
Field (폼 — 라벨 · 설명 · 오류)
수치 · 규칙의 원본은 specs/components/field.md · field.yaml 이다 — 2026-10-01 SEED Field 구조로 정했다. 옛 Label · Form 스펙과 v62 Form layout · v75 Form validation 의 규칙을 여기로 합쳤다(옛 글은 바로 앞 백업 DESIGN.history/v114-korean-line-break.md 의 Form layout · Form validation 절, 옛 스펙은 specs/components/label.history/ · form.history/). 이 절은 토큰과 닿는 자리만 모은다.
짜임
Field 는 머리(라벨 · 필수 점 또는 "선택" · 보조 액션) · 입력 · 꼬리(설명 또는 오류 · 글자 수)를 8 간격으로 쌓는다. 머리 · 꼬리는 좌우로 2 들어온다. 입력은 Text Input · Textarea · Select · Input Button · Checkbox · Radio · Select Box 묶음이고, 2026-10-09 부터 Slider(머리 오른쪽에 지금 값) · Input OTP · Color Swatch 묶음 · Icon Picker 도 감싼다.
| 부위 | 값 |
|---|---|
| 라벨 | t5 16px · 500(bold 700) · fg-neutral — 오류여도 그대로 |
| 필수 점 | 6px(0.375rem) fg-critical — 라벨 끝, 위 4 · 왼쪽 2. 화면 읽기 프로그램에는 숨기고 칸의 aria-required 로 알린다 |
| "선택" | t4 14px · 줄 높이 22 · fg-neutral-subtle |
| 설명 | t4 14px fg-neutral-subtle(앞 아이콘 16 은 선택) |
| 오류 | t4 14px fg-critical + 아이콘 16 — 설명 자리를 대신한다 |
| 글자 수 | t4 14px — 쓴 수 fg-neutral(비면 fg-neutral-subtle), 최대 fg-neutral-subtle, 오류면 둘 다 fg-critical |
| 폼 | Field 사이 spacing-x6 (24px) · 나란히 둔 두 칸 사이 spacing-x4 (16px, 768 미만은 한 줄에 하나) |
대비(라이트 · 다크): 라벨 16.41 · 13.42, 설명 · "선택" 5.50 · 6.09(시트 다크 5.27), 오류 5.06 · 6.08(시트 다크 5.27).
규칙
- 필수 표시는 2/3 규칙 — 한 화면 칸의 2/3 이상이 필수면 선택 칸에만 "선택", 아니면 필수 칸에만 점. 한 폼에 섞지 않는다. 칸이 하나뿐이면 붙이지 않는다.
- 라벨은 칸 위에 둔다 — 왼쪽 라벨 배치(옛 horizontal)는 두지 않는다. 라벨은 명사형, 마침표 없이.
- 오류 글은 무엇을 하면 되는지 짧게(Writing — 해요체 · 마침표) — "휴대폰 번호 10~11자리로 입력해주세요.". 맞음 · 확인 중은 설명 자리에 글로 — 초록 테두리 · 돌림 표시를 두지 않는다.
- 묶음(Checkbox · Radio · Select Box)의 칸 이름 · 오류도 Field 가 그린다 — 라벨이 묶음의 이름(
aria-labelledby)이다. - 오류가 생기면 화면 밖 알림 자리(
aria-live="polite")가 한 번 읽는다.
검증과 나가기
- 저장 · 신청 버튼은 켜 둔다. 누르면 비거나 틀린 칸마다 오류를 보이고 첫 오류 칸으로 포커스를 옮긴다(제출 시 검증 — 기본). 다 채울 때까지 버튼을 끄지 않는다.
- 잘못 넣으면 위험한 칸(보안 · 금융 — 비밀번호 확인 · 계좌번호 · 송금액)만 칸을 떠날 때 바로 알린다. 입력하는 동안 글자마다 오류를 띄우지 않는다.
- 서버 확인(아이디 중복)은 칸을 떠난 뒤 — 확인하는 동안 설명 자리에 "확인하는 중…", 결과도 설명 · 오류 자리에. 늦게 온 옛 응답이 새 응답을 덮지 않게 이전 요청을 취소한다.
- 작성 · 수정 화면에서 값이 바뀐 채 나가려 하면(뒤로 · 닫기 · 바깥 누름 · 시트 끌어내림) "작성한 내용이 사라져요" 를 묻는다(Alert Dialog). 바뀐 값이 없거나 자동 저장이면 묻지 않는다.
오류 글 꼴(v75 에서 옮겨 Writing 에 맞췄다)
| 규칙 | 오류 글 |
|---|---|
| 필수 | "{칸 이름}을(를) 입력해주세요." · 고르는 칸은 "{칸 이름}을(를) 골라주세요." |
| 최소 · 최대 길이 | "{N}자 이상 입력해주세요." · "{N}자 이내로 입력해주세요." |
| 숫자 범위 | "{N} 이상으로 입력해주세요." · "{N} 이하로 입력해주세요." |
| 형식 | "{칸 이름}을(를) {형식}으로 입력해주세요."(예: "휴대폰 번호 10~11자리로 입력해주세요.") |
| 이메일 | "이메일 주소를 확인해주세요(예: [email protected])." |
| 다시 입력 | "비밀번호가 서로 달라요." |
| 서버 확인 | "이미 쓰고 있는 {칸 이름}이에요." |
{칸 이름} 은 라벨과 같게 쓴다 — 오류만 보고도 어느 칸인지 안다.
기다림 — Skeleton · Progress Circle · Progress · Content Placeholder · Scroll Fog
2026-10-03 SEED Skeleton · Progress Circle · Pull To Refresh · Content Placeholder · Scroll Fog 와 Loading 패턴의 시간표로 새로 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/4ySVacsdnG4fgraR1HRK3G). 옛 Skeleton / Loading(v63) · Spinner / Progress(v67) 절을 대신한다. 수치 원본은
specs/components/skeleton.yaml·progress-circle.yaml·pull-to-refresh.yaml·progress.yaml·content-placeholder.yaml·scroll-fog.yaml, 쓰는 규칙은 같은 이름의.md(당겨서 새로 고침은progress-circle.md). 옛 스펙은skeleton.history·spinner.history·progress.history의v-pre-seed-loading.*. 토큰은 더하지 않았다 — v104 의gradient-shimmer-neutral·gradient-fade-mask·motion-duration-loop·motion-ease-easing을 쓴다.
나누기
| 이런 때 | 쓰는 것 |
|---|---|
| 목록 · 카드 · 상세를 처음 불러옴 | Skeleton — 틀은 그리고 데이터 자리만 |
| 섹션 새로 고침 · 목록 끝 더 불러오기 · 구조를 그릴 수 없는 화면 | Progress Circle — 요소 안 24 · 콘텐츠 가운데 40 |
| 저장 · 제출 | Button 의 로딩(원 14 · 14 · 16 · 18) |
| 올리기 · 받기 | 값 있는 Progress Circle 24 |
| 앱 목록 · 대시보드를 다시 받음 | 당겨서 새로 고침 — 원판 없는 원 24 |
| 예산 · 목표가 얼마나 찼나 | Progress — 막대(미터) |
| 이미지가 없거나 못 불러옴 | Content Placeholder — Image Frame 이 대체 그림으로 그린다(불러오는 동안은 같은 모서리의 Skeleton, "이미지" 절) |
| 스크롤 영역에 더 있음 | Scroll Fog |
시간표 — 1초 · 5초 · 10초
모든 불러오기가 따른다 — 1초 안에 오면 아무것도 보이지 않고(틀만), 1초부터 스켈레톤 · 원, 5초에 "평소보다 오래 걸리고 있어요.", 10초에 실패(Result Section + "다시 시도"). 요청 제한은 10초이고 저절로 다시 시도하는 것(읽기만)은 그 안에서만이다. 달 · 기간을 바꾸면 머리는 바로 바뀌고 바뀔 숫자 · 목록 자리만 기다린다 — 옛 달 숫자는 지운다. 같은 내용을 다시 받으면 보던 내용을 지우지 않는다(Result Section). 원본은 specs/components/skeleton.md 의 "기다리는 동안" 한 곳이다.
모양
| Skeleton | Progress Circle | Progress | Content Placeholder | Scroll Fog | |
|---|---|---|---|---|---|
| 크기 | 내용의 크기 · 글은 그 글자의 줄 높이(14 → 19) | 24(두께 3) · 40(두께 5) · 버튼 안은 Button | 높이 8 | 틀을 채움 · 그림 = 틀 높이의 50%(16 ~ 160) | 기본 20 · 가로 좌우 20 · 세로 위 20 · 아래 80 |
| 모양 | 모서리 글 8 · 그림 자리 4 · 6 · 8(Image Frame 대로) · 타일 12 · 카드 면 16 · 아바타 full · 화면 폭 사진 0 | 끝이 둥근 호 · 12시 시작 | 모서리 full | 제 모서리 없음 | 마스크 — 색이 없다 |
| 색 | 면 bg-neutral-weak + 흰 띠 gradient-shimmer-neutral(다크 짝) | 원 stroke-neutral-solid · 트랙 stroke-neutral-subtle, 톤 brand · staticWhite · inherit | 트랙 bg-neutral-weak · 채움 브랜드 글자색(넘친 한도만 fg-critical) | 면 bg-neutral-weak · 그림 stroke-neutral-weak | gradient-fade-mask |
| 움직임 | 반짝임 motion-duration-loop · motion-ease-easing | 1.2초 회전 + 호 · 채움 300ms | 채움 300ms | 없음 | 없음 — 늘 켜짐 |
| 모션 줄이기 | 띠가 멈춘다 | 돌지 않는 3/4 호 | 바로 바뀐다 | — | — |
쓰는 규칙
- 틀(머리 · 탭 · 제목 · 버튼 · 카드 면)은 처음부터 그린다 — 화면을 덮는 회색 막 "Loading" · 틀 없는 화면 가운데 원은 두지 않는다.
- 스켈레톤은 흰 면(
bg-layer-default·bg-layer-floating) 위에만 — 페이지 바탕(bg-layer-basement) 위에서는 같은 색이라 사라진다(1.00:1). 깜빡임(펄스)은 두지 않는다. - 스켈레톤과 원을 한 자리에 같이 쓰지 않는다.
- 막대는 미터다 — 기다림 · 올리기에 쓰지 않는다. 높이 · 색은 하나이고 주의 구간 색 · 달성 색은 없다(달성은 글자 "달성").
- 끝 흐림은 늘 켜 두고 흐린 쪽에 깊이만큼 여백을 둔다 — 시트 · 대화상자의 "넘칠 때만 아래 48"(2026-10-02)은 이것으로 바뀌었다.
- 깨진 이미지 아이콘 · 빈 이미지 칸을 두지 않는다.
접근성
- 기다리는 영역에
aria-busy, 화면에 상태 글 하나(role="status") — "불러오는 중…" · "평소보다 오래 걸리고 있어요." 를 한 번씩 읽는다. 결과는 Result Section 이 알린다. - Progress Circle 은
role="progressbar"— 이름 "불러오는 중", 값 글 "40%"(영어 · 세 점을 쓰지 않는다). Progress 는role="meter"— 이름 "식비 예산 400,000원 중 350,000원". - 스켈레톤 · 끝 흐림 · 대체 그림의 아이콘은 장식이다.
이미지 — Image Frame · Aspect Ratio · Logo Tile
2026-10-04 SEED Image Frame · Aspect Ratio 와 groo 의 물건 타일 · 카드 그림 규칙으로 새로 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/G351nuKcYX2xhorvA5UD6X, 1A · 2A · 3A · 4B · 5A · 6B · 7A · 8A · "따라오는 것"). 수치 원본은
specs/components/image-frame.yaml·card-art.yaml·aspect-ratio.yaml·logo-tile.yaml, 기관 색은institution-colors.yaml, 쓰는 규칙은image-frame.md·aspect-ratio.md·logo-tile.md. 옛 Aspect Ratio(v72) · Carousel(v71) 절은 걷었다 — 옛 스펙은specs/components/aspect-ratio.history·carousel.history의v-pre-seed-image.*. 토큰은 v118 의stroke-neutral-overlay하나를 더했다(이미지 위 투명 윤곽 — Avatar 의 테두리도 이 색).
나누기
| 보이려는 것 | 쓰는 것 |
|---|---|
| 사람 | Avatar — 원, 사진 또는 이니셜 + 이름 색 |
| 은행 · 증권 · 카드 · 코인 · 금 · 회사(물건) | Logo Tile — 각진 타일, 기관 색 + 첫 글자(그림이 있으면 덮는다) |
| 사진 · 카드 그림 · 규정 그림 | Image Frame |
| 카테고리 · 기능 | List 의 타일 — 옅은 색 + 아이콘 |
| 그림이 아닌 비율 상자(동영상 · 지도) | Aspect Ratio |
| 그림 여러 장 | Scroll Fog row 가로 줄 + Indicator("1 / 12" · "+9") — Carousel 은 걷었다 |
모양
| Image Frame | Logo Tile | Aspect Ratio | |
|---|---|---|---|
| 비율 · 크기 | 1:1 · 2:1 · 16:9 · 4:3(기본) · 6:7 · 4:5 · 2:3 · 카드 1.586 | 32 · 40(기본) · 48 | Image Frame 과 같은 여덟, 기본 4:3 |
| 모서리 | 폭으로 — 24 이하 4 · 48 이하 6 · 그 위 8 · 화면 폭 0 | 크기 × 0.3 — 10 · 12 · 14 | 0 |
| 윤곽 | 안쪽 1px stroke-neutral-overlay(v118 — 검정 4.7% · 다크 흰 5%), 그림 위에 늘 | 같다 | 없다 |
| 맞춤 | 사진 · 카드 그림 cover, 로고 contain(흰 판 static-white) | 카드 그림은 옅은 판 위 카드 전체 · 로고는 흰 판 위 contain | 동영상 cover |
| 불러오는 동안 | 같은 모서리의 Skeleton(면 bg-neutral-weak + 반짝임) | 첫 글자 먼저 — 그림이 오면 덮는다 | — |
| 없음 · 실패 | Content Placeholder(10초가 지나도 안 오면 실패) | 첫 글자 그대로 | — |
그림 위 요소
네 모서리에 하나씩, 틀 하나에 둘까지, 틀 가장자리에서 6(spacing-x1_5) — 틀의 짧은 변이 80 이상일 때만. 상태 · 분류는 Badge solid, 장수 · 길이는 Indicator(알약 · overlay-dim-dark 검정 65% 두 모드 같게 · static-white 11/15 500 · 좌우 6 · 위아래 2 · 높이 19 — 흰 그림 위 7.00:1). 관심(하트) 버튼 · 콘텐츠 종류 아이콘 · 점 지시자 · 화살표 · 자동 넘김은 두지 않는다.
카드 그림
- 비율 1.586(ISO 카드) — 목록 56 · 혜택 격자 · 상세 모두 같다. 최대 높이로 비율을 바꾸지 않는다.
- 세로 그림(원래 폭 < 높이)은 시계 방향으로 90° 돌려 가로 틀을 cover 로 채운다 — 다 받은 뒤 방향을 정한다.
- 그림이 없으면 아는 카드사는 카드 면(기관 색 한 색 + 회사 · 카드 이름, 폭 96 미만은 회사 첫 글자), 모르는 카드사는 Content Placeholder(카드 아이콘). 광택 띠 · 그라디언트 · 브랜드 파랑 대역은 두지 않는다.
- 상세는 그림이 떠도 카드 이름을 글로 둔다. 단종은 흐리지 않고 "단종" 배지.
기관 색 — 브랜드 hex 는 표 하나에만
은행 · 증권 · 카드사 · 코인 · 금 기관의 브랜드 색은 디자인 토큰이 아니라 데이터다 — 모드를 따르지 않고(라이트 · 다크 같다), 기관이 늘면 행이 는다. 그래서 머리말 colors 가 아니라 specs/components/institution-colors.yaml(78곳 — 자산 70 + 카드사 8)에 둔다. 브랜드 hex 를 화면 · 컴포넌트 · 제품 코드에 따로 적지 않는다 — 웹 · 앱은 그 표에서 만든 파일(레시피 lib/institution-colors.ts — 앱도 같은 표에서)과 찾기 규칙(기관 이름으로만 — 공백을 뺀 이름 · 별칭이 같으면 그 기관, 아니면 든 가장 긴 이름)만 쓴다. 토큰이 아닌 raw 색은 이 표와 차트 팔레트뿐이다(앱의 "chart palette · bank colors 는 raw palette 예외" 가 가리키는 자리).
- 같은 회사는 한 색 — 하나 #008485 · NH농협 #00A651(두 표가 달랐다).
- 글자색은 표의
text— 흰 글자(static-white)가 4.5:1 이상이면 흰색, 아니면 짙은 글자(라이트fg-neutral· 다크fg-neutral-inverted). 둘 다 모자라던 중간 밝기 다섯 곳은 명도만 고쳤다(원래 색은ci). 78곳 모두 4.52:1 이상이다. - 표에 없는 기관은 Logo Tile 이 Avatar 의 이름 색(차트 10색 +
fg-neutral-inverted)을, 카드 면이 Content Placeholder 를 쓴다.
접근성
- 이름 옆 그림 · 타일은 장식이다 — 그림
alt="", 타일은 첫 글자까지 숨긴다. 이름을 한 번만 읽는다. 혼자면 이름(그림의alt· 타일의role="img"+aria-label)이고, 실패해도 그 이름이 대체 그림 · 첫 글자에 남는다. - Indicator 는 보이는 글("+9") 대신 무엇의 수인지 읽는 글("사진 9장 더 있음")을 읽는다.
- 파일 이름 · "Image" · "logo" 를 이름으로 두지 않는다. 마우스에 그림을 키우지 않는다.
화면 틀 · 이동 — Top Navigation · Bottom Navigation · Side Navigation · Side Panel · Pagination · Floating Action Button
2026-10-04 SEED Top Navigation · Bottom Navigation · Side Navigation · Side Panel · Pagination · Table Pagination · Floating Action Button 구조로 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/B6tsgbw356Kf2Zumvm2v6a, 열하나 + 따라오는 것). 수치 원본은
specs/components/top-navigation.yaml·bottom-navigation.yaml·side-navigation.yaml·side-panel.yaml·pagination.yaml(+infinite-list.yaml) ·table-pagination.yaml·floating-action-button.yaml, 쓰는 규칙은 각 스펙 md 다. 화면 틀(문턱 · 머리 · 화면을 옮길 때 · 랜드마크)과 안전 영역은 Layout 의 "화면 틀" · "Safe Area" 절. 옛 Sidebar · Sheet(옆 패널) · Pagination 절은 다시 정했고, Breadcrumb · Navigation Menu 는 걷었다(SEED 에 없다 — 데스크톱의 위치는 사이드바의 지금 항목이 알린다).
나누기
| 자리 | 0 – 767 | 768 – 1279 | 1280 이상 |
|---|---|---|---|
| 화면 맨 위 | Top Navigation 56 | Top Navigation(Desk 데스크톱 머리 — HR 은 없음) | 같다 |
| 주 메뉴 | Desk Bottom Navigation · HR ☰ → Side Panel(왼쪽) | Side Navigation 접힘 56 | Side Navigation 펼침 240 |
| 긴 목록 | 끝없이 불러오기 | 상황에 따라 — Pagination · 끝없이 불러오기 · 묶음 옮기기(Layout "목록 넘기기") | 같다 |
| 데이터 표 | Table Pagination | Table Pagination | Table Pagination |
| 화면의 주 동작 | 탭 바 가운데 + · 탭 바 없는 화면은 Floating Action Button | 머리의 버튼 | 같다 |
모양
| 값 | |
|---|---|
| Top Navigation | 높이 56(위 안전 영역 더함) · bg-layer-default · 선 · 그림자 없음 · 아이콘 버튼 상자 44(= 누르는 영역) · 아이콘 24 · 화면 끝 6 · 버튼끼리 붙음 · 제목 왼쪽 — 탭 첫 화면 text-t8 22 / 30, 그 아래 text-t6 18 / 24, 700 · 글 버튼 44 · 좌우 10 · text-t5 500 · 누름 bg-layer-default-pressed + 2px 축소 · 알림은 점만 · z-sticky |
| Bottom Navigation | 떠 있는 알약 66(줄면 48) · 좌우 14(36) · 아래 max(14, 안전 영역 − 6) · 최대 480 · bg-layer-floating(불투명) · shadow-s3 · 안쪽 1px stroke-neutral-subtle · 5칸 · 아이콘 24 · 라벨 text-t1 11 / 15 고정 크기 · 500 · 지금 탭 fg-neutral + 선 2.5 · 다른 탭 fg-neutral-subtle + 선 2 · 가운데 + 원 44 브랜드 채움 · z-sticky |
| Side Navigation | 240 · 접힘 56(layout-sidebar · layout-sidebar-collapsed) · 흰 면 bg-layer-default + 오른쪽 1px stroke-neutral-subtle · 머리 64 · 접기 버튼 40 · 18 · 항목 44 · 아이콘 20 · text-t4 500 · 모서리 10(radius-r2_5) · 묶음 이름 text-t4 700 · 지금 항목 bg-neutral-weak-pressed + fg-neutral(굵기 500 그대로 — 2026-10-08) · 접힌 사이드바의 펼침 메뉴는 Menu 표면 · 폭 200 · 줄 44, 1280 미만에서도(Menu Sheet 규칙의 예외 — 2026-10-08) |
| Side Panel | 왼쪽(768 미만 주 메뉴 — 화면 폭의 80%) · 오른쪽(1280 이상 — 480 · 720 · 960) · 높이 전체 · 모서리 · 그림자 · 선 없음 · bg-layer-floating · 딤 overlay-dim-light · overlay-dim-dark · 머리 24 / 24 / 16 · 제목 text-t8 · 닫기 상자 52 · 아이콘 22 · 넘칠 수 있는 본문은 Scroll Fog 위 20 · 아래 80 · z-modal |
| Pagination | 칸 40 × 40 · 사이 0 · text-t4 700 · 모서리 8 · 지금 쪽 bg-neutral-inverted + fg-neutral-inverted · 이전 · 다음 아이콘만 16 · 9칸(480 이상) · 7칸 · 끝 쪽은 40 빈 칸 · 누르는 영역은 위아래만 44 |
| Table Pagination | 한 줄 40 · Select medium(최소 96 · 폭과 상관없이 — Select 1280 규칙의 예외, 2026-10-08) "{n}개" + "씩 보기" · 범위 "11-20" + "/ 총 N개"(목록 최대 240) · 이전 · 다음 40 — 끝에서 막힘 · 표 아래 12 |
| Floating Action Button | 원 56 · 아이콘 24 · 브랜드 채움 · 흰 아이콘 · shadow-s3 · 오른쪽 아래 화면 끝 · 아래 고정 요소에서 20 + 안전 영역 · 화면에 하나 · z-sticky |
쓰는 규칙
- 상단 바 — 높이 56 은 모든 화면이 같다. 스크롤해도 선 · 그림자를 긋지 않는다. 오른쪽 아이콘은 2개 권장 · 3개까지(넘치면 ⋯ + Menu · Menu Sheet), 글 버튼은 하나. ← 는 들어온 화면으로(앞 화면이 없으면 상위 화면)가 기본이고 화면마다 상위 화면(Hierarchy)을 고를 수 있다, ✕ 는 모달 · 독립 흐름만. 투명 바(
tonetransparent)는 사진이 화면 위를 채우는 상세에서만 — 스크롤하면 바탕이 채워진다(SEED · 2026-10-22 사용자 결정 5C, 막 · 누름 바탕은 열린 일). - 하단 탭 바 — 다섯 칸이 어느 화면에서나 같다(더 나누면 화면 위 Tabs). 가운데 + 는 그 화면의 추가 — 이름은 화면마다("거래 추가" · "일정 추가"). 아래로 스크롤하면 48 로 줄되 이름은 남고, 누르면 펴진다. 탭마다 스크롤을 기억하고, 지금 탭을 다시 누르면 맨 위 · 첫 화면.
- 사이드바 — 1280 이상 펼침 · 768 ~ 1279 접힘, 손으로 접은 것은 기억. 하위가 있는 항목은 펼치기만, 하위가 지금이면 저절로 펼침. 접혔을 때 하위는 아이콘 옆 펼침 메뉴(1280 미만이어도 Menu Sheet 로 바꾸지 않는다 — 2026-10-08), 단독은 이름 말풍선. 긴 이름은 줄을 바꾼다.
- 옆 패널 — 왼쪽은 768 미만의 주 메뉴(HR 폰 — 이동하면 닫고, 지금 묶음을 펼친 채 연다), 오른쪽은 1280 이상의 보조 작업(1280 미만은 Bottom Sheet). 아래 · 위 패널은 두지 않는다.
- 목록 넘김 — 상황으로 고른다(Layout "화면 틀" 의 "목록 넘기기", 2026-10-23 사용자 결정). 쪽 단위로 훑는 데스크톱 목록은 Pagination 이 맞을 수 있고(쪽은 주소에 — 칸은 링크), 스크롤로 내려가는 목록(폰 · 긴 목록)은 끝에 닿으면 저절로 더 불러오는 쪽이 자연스럽다(받는 중 · 다시 시도 · 끝 글). 달처럼 자연스러운 묶음이 있는 목록은 묶음 옮기기가 쪽 넘김이다(가계부 거래 — 달 이동). 데이터 표는 Table Pagination. 칸 40 은 누르는 영역 44(v106)의 예외다(위아래만 44 — 사용자 결정 2026-10-04).
- 떠 있는 버튼 — 탭 바 없는 폰 화면의 주 동작 하나. 글을 붙이거나 스크롤에 접지 않는다.
접근성
- 머리는
header(main밖), 주 메뉴는 이름 있는nav("주 메뉴"), 본문 바로가기 링크. 화면을 옮기면 맨 위 + 초점을 제목(h1)으로, 문서 제목은 "{화면 제목} - 그루 담다". - 탭 · 사이드바 항목은 링크 + 지금 화면
aria-current="page"(앱은 selected). 사이드바의 부모 · 접기 버튼은aria-expanded. 사이드바의 지금 항목은 한 단계 짙은 바탕 · 짙은 글자로만 보인다 — 굵기는 그대로(1.4.1 ⚠, 사용자 결정 2026-10-08). - 아이콘만 있는 버튼(상단 바 · + · 떠 있는 버튼)은 이름 필수 — 알림 점은 이름에 넣는다("알림, 새 알림 있음").
- Pagination —
nav"페이지 탐색" · 칸 "N페이지" · 끝 쪽에서 초점을 지금 쪽으로 · 쪽이 바뀌면 알린다. 칸 40 은 AA(2.5.8) ✓ · AAA(2.5.5) ⚠.
입력 — Slider · Toggle · Input OTP · Color Swatch · Icon Picker
2026-10-09 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/CwVJDATSmLtwQoH67wh1zj, 1B · 2C · 3B · 4B · 5A · 6B · 7A · 8A · 9A · 10A · 11B · 12C · 13B · 14B · 15A · 16A · 17A · 18A · 19B · 20A · 21A · 22A + 따라오는 것). SEED 가 컴포넌트로 가진 것은 Slider 와 Toggle Button(코드만)뿐이라, 인증 코드 칸 · 색 고르기 · 아이콘 고르기는 SEED 의 원칙(Text Input 의 "Input을 나누지 말고" · Iconography)에서 groo 가 정했다. 수치 원본은
specs/components/slider.yaml·toggle.yaml·input-otp.yaml·color-swatch.yaml·icon-picker.yaml, 아이콘 세트는category-icons.yaml, 쓰는 규칙은 각 스펙 md 다. 옛 Slider · Toggle · Input OTP(v69) 절은 다시 정했고 Toggle Group 은 걷었다 — 옛 스펙은 각.history의v-pre-seed-input.*. 토큰은 더하지 않았다.
나누기
| 고르는 것 | 쓰는 것 |
|---|---|
| 범위 안의 자리(임계값 · 비율) · 2 ~ 5단계(별점) | Slider |
| 정확한 숫자 · 금액 | Input — 숫자 키보드 · 뒤 단위 |
| 단추 하나가 그 자리에서 켜고 끄는 상태(관심 · 고정 · 비밀값 보기) | Toggle — 아이콘 단추. 다른 화면으로 가는 눈(금액 가리기 설정)은 Toggle 이 아니다(2026-10-16) |
| 같은 내용을 2 ~ 4가지로 바로 다르게 보기 | Segmented Control |
| 2 ~ 4개 짧은 폼 값 · 거르기 · 제안 | Chip |
| 5개 이상 | Select |
| 누르는 순간 적용되는 설정 줄 | Switch |
| 저장해야 적용되는 켜고 끄기 · 할 일 완료 | Checkbox |
| 메일로 받은 인증 코드 | Input OTP — Input 한 칸 |
| 항목에 붙일 색 | Color Swatch |
| 카테고리 · 저축 목표의 아이콘 | Icon Picker — Input Button + 시트 · 팝오버 |
Toggle Group 은 두지 않는다 — 하나 고르기는 Segmented Control(2 ~ 4) · Chip, 여럿은 Chip, 5개 이상은 Select 다. 글이 있는 켜고 끄기 단추(SEED Toggle Button · 옛 groo Toggle)도 두지 않는다.
모양
| 값 | |
|---|---|
| Slider | 손잡이 줄 44(줄 전체가 누르는 자리) · 트랙 4 stroke-neutral-weak · 채움 fg-neutral · 손잡이 원 20 bg-neutral-inverted(누르는 동안 24) · 테두리 · 그림자 없음 · 머리 값 16 / 22 · 700 · 말풍선 13 / 18 · 500(끄는 동안 · 호버 · 키보드 포커스) · 아래 양 끝 표식 · 눈금은 2 ~ 5 구간만(트랙을 끊는 틈 4) · 막힘 bg-disabled · fg-disabled |
| Toggle | 보이는 40 · 누르는 44 · 아이콘 20 · 바탕은 누름 · 호버에만 · 끔 fg-neutral-muted + 선 2 · 켬 fg-neutral + 선 2.5 · 브랜드 채움 위는 흰 아이콘 · 상단 바 안은 상자 44 · 아이콘 24 · 끔도 fg-neutral(굵기 · 아이콘으로만 가른다) |
| Input OTP | Input 상자형 한 칸 — large 52 · medium 40 · 숫자만 앞 6자리 · 고정폭 숫자 · 아래 설명 줄 · 다시 받기 Button neutralWeak medium(칸 아래 12, 보낸 뒤 60초 막힘) |
| Color Swatch | 원 40 · 누르는 44 · 5 × 2(사이 12 · 폭 248) · 차트 10색(라이트 700 · 다크 800-dark) 진한 채움 · 고름 = 2 띄운 2px stroke-neutral-contrast 고리 + 체크 16 fg-neutral-inverted |
| Icon Picker | 트리거 Input Button · 1280 미만 Bottom Sheet · 이상 Popover 408 · 찾기 칸 밑줄형 · 묶음 머리 14 · 500 · 칸 48 · 모서리 12 · 아이콘 24 · 고른 칸 안쪽 2px stroke-neutral-contrast + 선 2.5 |
쓰는 규칙
- 요청 중에도 막지 않는다 — 누르는 순간 저장되는 Toggle · Switch 와 손을 뗄 때 한 번 저장되는 Slider 는 화면을 바로 바꾸고 요청은 뒤에서 보낸다. 실패하면 되돌리고 그 자리에서 알린다(Slider 는 Field 오류, Toggle 은 Snackbar). 단계마다 저장 · 지연 저장 · 저장 버튼은 두지 않는다.
- 슬라이더 값 — 지금 값은 Field 머리 오른쪽에 늘, 끄는 동안 말풍선, 아래 양 끝 표식. 단계마다 숫자를 늘어놓지 않는다. 2 ~ 5단계 고르기도 Slider 다(옛 "3개 이하 금지" 는 걷었다).
- 켜고 끄는 단추 — 이름은 고정하고 켬은
aria-pressed. 아이콘은 지금 상태를 그린다 — 키가 가려져 있으면eye-off. 다른 화면으로 가는 버튼(순자산 카드의 금액 가리기 눈 → 설정)은 켜고 끄는 단추가 아니라aria-pressed를 달지 않는다(2026-10-16). 모으기 단추(관심 · 고정)의 꺼짐은 사선 없이(Iconography). 켬에 바탕을 칠하지 않는다. 상단 바에서는 끔도 이웃 버튼과 같은 진한 색이다(2026-10-09). - 인증 코드 — 칸을 나누지 않는다. 붙여넣기 · 자동 채우기에서 숫자만 뽑고(
one-time-code· 숫자 키보드), 6자리를 채워도 저절로 보내지 않는다. 설명 줄 "10분 안에 입력해주세요 · 5번 틀리면 다시 받아요." 를 늘 두고, 다시 받기 단추는 남은 초를 붙여 막는다 — 시계로 세지 않는다. - 색 — 새 항목은 v110 배정 순서에서 쓰지 않은 첫 색으로 시작한다(늘 빨강이 아니다). 고치기는 고르지 않으면 색을 바꾸지 않고, 팔레트 밖 색 · 색 없는 항목은 격자 앞 "지금 색" · "자동" 칸으로 보인다. 색을 꼭 고르게 하지 않는다.
- 아이콘 — lucide 전체가 아니라
category-icons.yaml의 세트(148개 · 13 묶음)만 연다. 한국어 이름 · 찾는 말로 찾고, 0건이면 "'{검색어}'에 대한 아이콘이 없어요". "없음" 은 두지 않는다 — 기본은 태그. 세트 밖으로 저장된 아이콘은 그대로 그린다.
접근성
- Slider 이름은 Field 라벨,
aria-valuetext에 단위("80%"), 키보드는 APG(포커스한 손잡이의 Home · End, PageUp · PageDown 10단계). 트랙을 눌러도 고른다(끌기 대신). - Toggle 은
<button aria-pressed>+ 고정 이름(앱Semanticstoggled — 라벨에 상태를 넣지 않는다). - Input OTP 는 입력 하나 — Field 라벨 ·
aria-describedby(설명 · 오류) · 오류 알림. 코드를 보내면 초점을 칸으로. - Color Swatch 는 radiogroup(이름 = Field 라벨) · 칸 이름 = 색 이름 · 묶음에 Tab 하나 + 2차원 화살표.
- Icon Picker 격자는 listbox · 칸 이름 = 한국어 이름 · 격자에 Tab 하나 + 2차원 화살표 · 찾으면 결과 수를 한 번 알린다.
- 누르는 영역은 44 이상 — 슬라이더 손잡이 줄 44 · 토글 44 · 색 칸 44 · 아이콘 칸 48. 인증 코드 칸 medium 40 은 1280 이상 데스크톱 웹만이다(Input 과 같다).
펼치고 접기 · 나누기 — Accordion · Collapsible · Tree View · Resizable · Scroll Area · Scroll Auto Hide
2026-10-10 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/9uvjeFyjFXc7TaWnpnnQ6H, 1B · 2A · 3A · 4A · 5A · 6A · 7C · 8A · 9A · 10A · 11A · 12B · 13A · 14A · 15A + 따라오는 것, 스펙을 쓰다 나온 16D · 17B). SEED 가 컴포넌트로 가진 것은 Accordion(rootage 3.0.2 · react 2.0.0)과 Breeze 의 Scroll Auto Hide 뿐이라, Collapsible(Accordion 가이드의 한 줄) · 나무 · 나누기 · 스크롤바는 SEED 의 원칙과 groo 의 이웃 결정(List · Card · Side Navigation · Scroll Fog · v104 모션)에서 groo 가 정했다. 수치 원본은
specs/components/accordion.yaml·collapsible.yaml·tree-view.yaml·resizable.yaml·scroll-area.yaml·scroll-auto-hide.yaml, 하위 줄은list.yaml, 카드 안 아코디언은card.yaml이고 쓰는 규칙은 각 스펙 md 다. 옛 Accordion · Collapsible(v70) · Scroll Area · Resizable(v71) · Treeview(v73) 절은 다시 정했다 — 옛 스펙은 각.history의v-pre-seed-collapse.*. 토큰은 더하지 않았다.
나누기
| 하는 일 | 쓰는 것 |
|---|---|
| 상세가 긴 항목 여럿을 묶어 접는다(카드 혜택 · 유의사항) | Accordion — 화면 · 카드 안은 inline, 혜택 상세 시트 · 대화상자는 separated |
| 상세 하나를 접고 편다(분할 내역 · 빠르게 맞추기 · 상세 검색 조건) | Collapsible — Accordion 항목 하나의 모양 |
| 부모 · 하위 두 단계에서 줄은 편집을 열고 하위만 접는다(카테고리) | List 하위 줄 — 줄 앞 꺾쇠 단추 |
| 여러 단계에서 하나를 골라 옆에 그 내용을 본다(HR 부서) | Tree View — APG 트리 |
| 목록 · 상세 두 패널의 목록 폭을 바꾼다(HR 관리, 768 이상) | Resizable split |
| 대시보드 위젯의 크기를 바꾼다(HR 편집 모드) | Resizable widget + ⋮ "크기" |
| 넘친 내용을 스크롤한다 | Scroll Area — 기본 스크롤 + 전역 스크롤바 한 벌 |
| 목록을 넓게 보려고 보조 머리를 스크롤에 숨긴다(폰 원장 머리) | Scroll Auto Hide |
| 읽어야 하는 긴 글(규정 · 유의사항 제목 · 부서 이름) | 자르지 않는다 — 줄을 바꾼다 |
모양
| 값 | |
|---|---|
| Accordion | 트리거 위아래 16 · 좌우 24 · 제목 16 / 22 · 500 · 설명 13 / 18 · 500 fg-neutral-subtle · 꺾쇠 20 fg-neutral-subtle · 54(설명이 있으면 74) · 앞 아이콘 22 · 사이 12 · 폰 · 데스크톱 같음 · inline 들인 선 24 stroke-neutral-subtle · separated Card 면(16 · 1px stroke-neutral-weak · 사이 8 · 그림자 없음) · 누름 = List 누름(들임 6 · 모서리 10 · bg-layer-default-pressed · 콘텐츠만 2px) · 펼친 내용 0 / 24 / 16 · text-article-note · fg-neutral-muted · 모두 펼치기는 Card 머리 동작 모양(보이는 32 · 누르는 44) · 포커스 링은 트리거 안쪽 |
| Collapsible | 트리거는 Accordion 항목 하나(54 · 74) — 흰 면 · 시트의 줄 · 카드 면의 머리(펼친 내용 아래 24) · 경고 상자의 아래 줄(좌우 16 · 위 선 stroke-warning-weak · 누름 bg-warning-weak-pressed) |
| List 하위 줄 | 줄 앞 꺾쇠 단추 44(모서리 10 · chevron-right 20 · 펼치면 90°) · 줄 앞 4 · 하위 줄은 부모 제목 자리 104 · 하위가 없는 줄도 꺾쇠 자리를 비워 부모 타일이 52 에 선다(17B) |
| Tree View | 줄 44 · 위아래 12 · 좌우 8 · 단계마다 20 · 모서리 10 · text-t4 · 꺾쇠 16(칸 20 · 표시만 — 누르는 자리는 줄 전체) · 아이콘 16 · 사이 6 · 고름 bg-neutral-weak-pressed · 누름 bg-layer-default-pressed + 콘텐츠만 2px · 패널 가장자리 8 · 노드 동작 ⋮ 하나(40 · 누르는 44) |
| Resizable | 선 1px stroke-neutral-weak(올리기 · 초점 · 끌기에 stroke-neutral-solid) · 손잡이 표시 4 × 24 stroke-neutral-solid · 누르는 폭 16 · 목록 25%(20 ~ 40%) · 위젯 모서리 24 · 표식 9 × 9 2px stroke-neutral-solid · 자리표시 브랜드 옅은 바탕 + 1px 브랜드 점선 · 모서리 16 |
| Scroll Area | 6px 알약 · 막대 stroke-neutral-solid · 바탕 투명 · Firefox thin + scrollbar-color 는 @supports not selector(::-webkit-scrollbar) 안 |
| Scroll Auto Hide | 스크롤 상자 맨 위 sticky · 스크롤 거리 1:1 · 끝나면 50% 스냅 motion-duration-d4 motion-ease-enter · translate3d 로만(높이 그대로) · 바탕 bg-layer-default |
쓰는 규칙
- 여럿을 함께 연다 — 아코디언은 늘 여럿을 열고, 목록 머리 오른쪽에 "모두 펼치기"(펼치면 "모두 접기")를 둔다. 항목은 둘 이상이고(하나면 Collapsible) 처음엔 모두 접혀 있다. 상세가 없는 항목은 꺾쇠 없는 그냥 줄이다 — 막힌 트리거 · 꺾쇠만 뒤집히는 줄을 두지 않는다.
- 줄 전체가 트리거 — Accordion · Collapsible 은 줄 전체를 누르고, 머리 글이 곧 이름이다. 이름은 고정하고 펼침은
aria-expanded가 알린다. 줄이 따로 하는 일(편집)이 있으면 줄 앞 꺾쇠 단추 44 로 접는다(카테고리 — "{카테고리} 하위 카테고리"). - 펼쳐도 그 자리에 — 저절로 스크롤하거나 초점을 옮기지 않고, 패널 안에 스크롤 상자를 두지 않는다. 꺾쇠 · 높이는
motion-duration-d6motion-ease-easing이고 모션 줄이기면 높이 움직임 없이 150ms 서서히 — 사이드바 하위 펼침 · 나무 · 하위 줄도 같다. - 자르지 않는다 — 제목 · 이름 · 규정 글은 줄을 바꿔 다 보인다. "더 보기" · 눌러서 상세로 잘린 글을 펼치지 않는다(Typography v114).
- 카드 상세 — 혜택 · 유의사항은 웹 · 앱 모두 카드 안
inline아코디언이고, 혜택 상세 시트 · 대화상자는separated다. - 원장 머리 — 폰 가계부의 소비 요약과 월 달력은 하나만 펼친다. 원장 머리(월 · 총액 · 주 달력)는 스크롤하면 숨는다 — 상단 바 · Line Tabs 는 숨지 않고 하단 탭 바는 제 규칙으로 줄어든다.
- 나무 —
Tab하나 · 화살표로 다닌다. 줄 전체가 누르는 자리라 부모 줄을 누르면(Enter·Space도) 고르면서 펴고 접고, 꺾쇠는 표시만이다(16D — SEED Accordion 의 "터치 영역은 Trigger 전체").→←는 고르지 않고 펴고 접기만 한다. 노드 동작은 나무 밖 ⋮ 하나, 머리말은 두지 않는다. - 나누기 — HR 관리의 768 이상에서만, 목록 20 ~ 40%(오른쪽은 60% 아래로 줄지 않는다) · 화면마다 폭을 기억 · 손잡이를 한 번 누르면 25 ↔ 40. 위젯 크기는 모서리를 끌거나 ⋮ "크기" 로.
- 스크롤 — 기본 스크롤 + 전역 한 벌이고 Radix ScrollArea 는 걷는다. 세로 스크롤바는 숨기지 않는다(가로 줄만 — Scroll Fog).
접근성
- Accordion · Collapsible 트리거는
heading > button(기본h3) ·aria-expanded·aria-controls, 펼친 내용에role="region"을 두지 않는다. 아코디언 트리거 사이↓↑(돌아가며) ·Home·End. 앱은 단추 + 펼침 상태로 읽고, 접힌 내용은 읽지 않는다. - Tree View 는
tree·treeitem(aria-level·aria-setsize·aria-posinset·aria-expanded·aria-selected) ·group, 나무 전체가Tab정지점 하나(roving tabindex).Enter·Space는 누르기와 같다. - Resizable 손잡이는
role="separator"· 이름 "목록 너비" ·aria-orientation· 값(지금 · 최소 · 최대 %). 끌지 않는 대안 — 손잡이 한 번 누르기 · 키보드 · 위젯 ⋮ "크기"(WCAG 2.5.7). - 안에 초점 가는 것이 없는 스크롤 상자는
tabindex="0"+role="region"+ 이름, 시트 · 대화상자 · 팝오버 안 상자는overscroll-behavior: contain. 숨는 머리는 모션 줄이기면 숨지 않고, 그 안으로 초점이 오면 드러난다. - 누르는 영역 — 트리거 줄 54 이상 · 모두 펼치기 · 꺾쇠 단추 · 나무 줄(부모 줄도 줄 전체 — 꺾쇠만 누르는 자리는 없다) · ⋮ 44. 위젯 모서리 24 는 AAA(2.5.5) ✗ — 같은 일을 ⋮ "크기" 로 한다. 나누기 손잡이 16 은 AA(2.5.8)도 ⚠ — 데스크톱 마우스 경계라 사용자가 정했고(12B) 같은 일을 키보드 · 누르기로 한다.
마무리 — Quantity Picker · Attachment Input · Footer
2026-10-15 정했다(사용자 결정 — 비교 페이지 https://claude.ai/artifact/KVyg5Kr95cYUkMT3vsxz1z, 1A · 2A · 3A · 4A · 5A · 6A · 7B · 8A · 9A · 10A + 따라오는 것, 스펙을 쓰다 나온 11D · 12A · 13B · 14A). SEED 가 컴포넌트로 가진 Quantity Picker · Attachment Input(rootage · React)과 조합 예시인 Footer(블록 코드)를 groo 에 처음 둔다 — 디자인 시스템의 마지막 묶음이다. 같은 날 Command(⌘K · cmdk)를 디자인 시스템과 제품에서 걷었다(아래 "Command" 절) — 그 자리였던 HR 역할 고르기는 Select Box 여럿 + "저장"(10A), 프로필 사진은 Avatar + 늘 보이는 버튼(6A)이다. 수치 원본은
specs/components/quantity-picker.yaml·attachment-input.yaml·footer.yaml(사진 바꾸기는avatar.yaml의 edit 축), 쓰는 규칙은 각 스펙 md 다. 옛 File Upload(v73) 절은 걷었다 — Attachment Input 이 대신한다. 토큰은 더하지 않았다.
나누기
| 하는 일 | 쓰는 것 |
|---|---|
| 작은 정수를 한 단계씩 — 흔한 값이 열 단계 안쪽(승인 필요 횟수 · 반복 간격 · 부여 시간 · 소요시간) | Quantity Picker |
| 흔한 값이 열 단계보다 먼 정수(반복 거래 "총 n회") · 돈 · 소수 | Input — 숫자 칸 |
| 날짜 부분 · 띄엄띄엄 이름 붙은 값(반복 일자 · 할부) | Select |
| 여럿 · 사진이 섞이는 첨부(거래 영수증 · 메모 · 휴가 증빙) | Attachment Input — 타일 |
| 파일 하나를 골라 바로 넘긴다(CSV · Excel 가져오기) | Attachment Input — 드롭존(1280 이상 웹) · 파일 선택 버튼(1280 미만 · 앱) |
| 사람의 프로필 사진 한 장을 바꾼다 | Avatar + "사진 바꾸기" · "사진 지우기" |
| 여럿을 골라 한 번에 반영한다(HR 사용자 역할) | Select Box 여럿 + "저장" |
| 사이트 맨 아래 — 탐색 · 정책 · 저작권 | Footer — 블록 조립 |
모양
| 값 | |
|---|---|
| Quantity Picker | 상자 1px stroke-neutral-weak · bg-layer-default · small 36 · medium 40 · large 52(모서리 8 · 8 · 12, 아이콘 16 · 18 · 22, 값 16 / 22 · 16 / 22 · 18 / 24 · 500) · 웹 폼 기본 responsive(1280 미만 52 · 이상 40) · 표 칸 36 · 선 1 × 16 stroke-neutral-subtle · 값 칸 좌우 8 · 가장 긴 값의 폭 · 누름 bg-layer-default-pressed + 그 버튼만 2px · 36 · 40 버튼은 누르는 자리 44 · 끝 fg-disabled(초점은 남는다) · 오류 안쪽 2px stroke-critical-solid · 로딩 원 16 · 18 · 22(Button ghost 의 원과 같은 값) |
| Attachment Input | 타일 80 · 모서리 12 · 1px stroke-neutral-weak · 아이콘 24 · 개수 12 / 16("3/10") · 사진 80(윤곽 stroke-neutral-overlay) · 파일 카드 160 × 80(좌우 16 · 썸네일 칸 48 · 이름 12 / 16 · 500 글자 단위 네 줄 · 넘치면 넷째 줄에 확장자 · 크기 11 / 15) · 사이 8 · × 20(4 걸침 · 구멍 24 · 누르는 44) · 올리는 중 원 24 · 실패 "다시 시도" · 대표 띠 24 · 줄은 화면 여백까지 + 끝 흐림 20 · 드롭존 높이 120 · 1px 실선 stroke-neutral-solid(끌기 stroke-neutral-contrast + bg-layer-default-pressed) · 안내 14 / 19 · 500 + "파일 선택" neutralWeak small · 항목을 누르면 메뉴(크게 보기 · 대표로 정하기 · 앞으로 옮기기 · 뒤로 옮기기 | 지우기) · 읽기 전용 · 끄는 사진은 불투명도 0.5(SEED) |
| Footer | 틀 1040(layout-max-content) · 위아래 40 · 좌우 32(1280 미만 24) · 영역 사이 40 · 위 선 · 브랜드 20 / 27 · 700 + 소개 13 / 18 · 사이트맵 열 최소 100 · 사이 32 · 열 제목 13 / 18 · 500 fg-neutral-muted · 링크 16 / 22 · 500 사이 16 · 선 stroke-neutral-subtle · 안내 영역 사이 16 · 정책 링크 14 / 19 · 500 fg-neutral-muted 사이 24 · 안내 글 13 / 18 fg-neutral-subtle · 저작권 14 / 19 · 500 · 소셜은 Button ghost large(사이 24) |
| Avatar 사진 바꾸기 | 108 아래 16 에 "사진 바꾸기"(neutralWeak small) · "사진 지우기"(ghost small · 사진이 있을 때만) · 올리는 중 원 위 딤 + 값 있는 원 24 · 실패는 Field 오류 글 |
| HR 역할 고르기 | 칸 없는 체크 상자(이름 16 · 500 + 역할 설명 13) 여럿 + 아래 "저장"(바뀐 것이 없으면 막힘) — 폰 · 데스크톱 같은 모양 |
쓰는 규칙
- 수량 칸은 치지 못한다 — 값 칸은 보기만 하고 한 번에 1 씩이다. 누르고 있어도 반복하지 않고 화살표 키도 없다. 흔한 값이 열 단계보다 먼 자리는 숫자 칸이다. 최소 · 최대는 데이터로 건다(승인 필요 횟수의 최대 = 고를 수 있는 승인자 수). 단위는 값 칸의 글("3회"), 제출은 정수다.
- 옆 칸과 같은 높이 — 수량 칸은 Input 처럼 웹 responsive · 앱 52, 표 칸은 36. 버튼 줄의 48 에 맞추지 않는다.
- 첨부는 한 줄 — 항목은 줄을 바꾸지 않고 옆으로 스크롤하며, 사진 · 파일 카드가 파일 종류대로 섞인다. 다 차면 타일이 막힌다. "n/최대" 는 서버의 개수 한도가 있을 때만 그린다.
- 다시 검사하고 그 자리에서 —
accept를 믿지 않고 형식 · 크기 · 개수를 다시 본다. 거절은 Field 오류 글 한 번("10MB 넘는 파일은 올릴 수 없어요."), 올리기 실패는 항목 덮개 + "다시 시도", 진행은 값 있는 원 24 다(막대를 쓰지 않는다). - 드롭존은 1280 이상 웹만 — 끌어 놓기가 없는 폰 · 앱은 "파일 선택" 버튼 + 파일 카드다. 상자 전체를 누르는 자리로 두지 않는다 — 키보드는 버튼으로 닿는다.
- 흐림은 사진의 두 상태만 — 막힘은 불투명도로 흐리지 않는다(v106). 예외로 사진 항목의 읽기 전용 · 끄는 중은 SEED 그대로 불투명도 0.5 이고, 파일 카드는 글 · 아이콘이
fg-disabled다(사용자 결정 13B). - 누르면 메뉴 — 항목을 누르면 1280 미만 Menu Sheet · 이상 Menu 로 크게 보기 · 대표로 정하기 · 앞으로 옮기기 · 뒤로 옮기기 | 지우기 — 끌지 않고 순서를 바꾸는 길이다(14A). 끝에서는 그 방향이 막히고, × 는 지름길로 남는다.
- 파일 이름 — 글자 단위로 네 줄까지 보이고(Typography v114 의 예외 — 11D), 넘치면 셋째 줄 끝을 "…" 로 줄이고 넷째 줄에 확장자를 남긴다. 보조 기술에는 전체 이름을 준다.
- 프로필 사진 — 늘 보이는 버튼으로 바꾸고 지운다. 마우스를 올려야 나타나는 덮개를 두지 않는다.
- 바닥은 블록 조립 — 순서는 SEED 그대로이고 필수 블록이 없다. 사업자 정보 · 연락처 · 소셜은 값이 생기면 넣는다(지어내지 않는다). 개인정보 처리방침은 로그인 전에도 닿는 바닥에 둔다. 저작권은 "© {해} 그루" 한 벌이다(홈 · SSO 로그인 · HR 문서 · Desk 설명서). groo-home 은 짜임 · 간격 · 글 크기만 따르고 색 · 글꼴은 홈 것을 쓴다 — 안내 글은 4.5 이상으로 짙게 한다.
- 권한은 저장 한 번 — 역할처럼 권한을 주는 여럿 고르기는 누를 때마다 저장하지 않는다.
접근성
- Quantity Picker 는
role="group"+ 이름(Field 라벨)이다. 버튼 이름은 "줄이기" · "늘리기", 끝은aria-disabled(초점이 남는다), 값 칸은aria-live="polite"·aria-atomic, 로딩은aria-busy. - Attachment Input 의 타일 이름은 "{칸 이름} 첨부, 3/10", × 는 "{파일 이름} 지우기", 항목 이름은 전체 파일 이름 + 크기 + 상태다. 포커스 링은 모두 부품 안쪽이다(가로 스크롤 줄이 바깥 링을 자른다). 순서 바꾸기는 끌기 · 항목 메뉴(포인터 한 번 — 2.5.7 ✓) · 키보드(Space · ← → · Space · Esc, 한국어 읽기 글) 셋으로 한다. 드롭존의 키보드 길은 "파일 선택" 버튼이다.
- Footer 는
<footer>(contentinfo) · 사이트맵<nav aria-label="사이트 지도">이고, 새 탭 링크는 보이지 않는 "(새 탭)" + ↗(장식)이다. - 누르는 영역 — 수량 버튼 · × 는 보이지 않는 여백으로 44, 첨부 타일 80, "파일 선택" 은 Button 의 44. 바닥의 글 링크(22 · 19)는 AAA ⚠ — SEED 와 같고, 간격 예외로 AA 는 ✓.
Pagination (v67 추가)
2026-10-04 다시 정했다 — 위 "화면 틀 · 이동" 절과
specs/components/pagination.md·table-pagination.md(SEED Pagination · Table Pagination). 옛 numbered · prev-next · load-more 변형, 지금 쪽 primary 채움, sm 32 · md 40 · lg 48 은 걷었다 — 폰의 긴 목록은 끝없이 불러오기이고 "더 보기" 버튼은 두지 않는다. 옛 스펙은specs/components/pagination.history/v-pre-seed-nav.*.
Sheet — 옆 패널 (v67 추가)
2026-10-04 다시 정했다 — 옆 패널은 Side Panel(
specs/components/side-panel.md— 왼쪽 · 오른쪽만, 평평). 위 "화면 틀 · 이동" 절. 아래에서 올라오는 것은 Bottom Sheet, 위에서 내려오는 패널은 걷었다. 옛 스펙은specs/components/sheet.history/v-pre-seed-nav.*.
Spinner / Progress (v67 추가)
2026-10-03 걷었다 — 스피너는 Progress Circle, 막대는 미터인 Progress 다(위 "기다림" 절,
specs/components/progress-circle.md·progress.md). 옛 스펙은spinner.history·progress.history의v-pre-seed-loading.*.
Stepper (v67 추가 · 기록 — 아직 SEED 와 다시 정하지 않았다)
다단계 form / 결재 흐름 / onboarding 시각화. 새 토큰 0 — primary + semantic + spacing 합성.
Variant
| Variant | 방향 | 사용 |
|---|---|---|
| horizontal (default) | 좌→우 | desktop form (HR 휴가 신청 3단계, Desk 가계부 분류 설정) |
| vertical | 위→아래 | mobile 또는 단계 라벨 길어 horizontal 부적절 시 |
| simple progress | 점 dot 진행 | minimal (Desk onboarding 5단계 dot indicator) |
State
| State | 시각 (step circle) |
|---|---|
| completed | success 채움 + ✓ icon (text-on-accent) |
| current | primary 채움 + 단계 번호 (text-on-accent) + outer ring border-focus 2px |
| pending | surface-input 배경 + 단계 번호 (text-tertiary) |
| error | error 채움 + ! icon (단계 검증 실패) |
| disabled (skip 가능 단계) | text-disabled + opacity 0.5 |
Anatomy
- step circle: 32×32 default, sm 24, lg 40 (
touch-min44 충족 위해 sm은 padding 보강) - 라벨: circle 아래 (horizontal) 또는 우측 (vertical),
caption(12/400) - connector line: step 사이 1px
border-default(pending) 또는 2pxsuccess(completed) - gap: step 사이
lg(16px) horizontal,md(12px) vertical
Layout
- horizontal: viewport
breakpoint-md(768px) 이상에서만 사용. 그 이하는 vertical 자동 전환 - vertical: 좌측 dot column + 우측 라벨/내용
- 4단계 이상: 모바일에서 vertical 권장 (horizontal 너무 좁음)
Sequential vs Free navigation
- sequential (default): 이전 단계 완료 후 다음 단계 진입 가능. 비완료 단계 클릭 비활성
- free: 모든 단계 자유 이동 (settings 메뉴 등). 단, 의존성 있는 단계는 disabled
Motion
- 단계 전환: completed↔current 색 트랜지션
motion-duration-base(200ms)motion-ease-out - connector line fill (next step 진입 시): width 0 → 100%
motion-duration-slow(300ms)motion-ease-out - error 단계: 진동 (
shakekeyframes 200ms) —prefers-reduced-motion: reduce시 색만 변화
Accessibility
-
<nav aria-label="결재 단계">wrapper -
<ol>+<li>(semantic order) - current step
aria-current="step" - completed step
aria-label="단계 1: 신청자 정보, 완료", currentaria-label="단계 2: 기간 입력, 현재", pendingaria-label="단계 3: 사유, 미진행" - 키보드: Tab으로 단계 이동 (sequential은 disabled 단계 skip)
- sequential mode 진입 차단 시 screen reader "이전 단계 완료 후 진입 가능" 안내
- error 단계:
aria-invalid="true"+ alert text 동반
HR / Desk 듀얼 브랜드
spec brand-neutral. brand 파일 — HR(결재 단계 horizontal, sequential), Desk(onboarding dot indicator simple, free 옵션).
Breadcrumb (v68 추가)
2026-10-04 걷었다 — SEED 에 없고, 데스크톱의 위치는 사이드바의 지금 항목(부모 자동 펼침)과 본문 제목이 알린다(화면 틀 · 이동 결정 9). 옛 스펙은
specs/components/breadcrumb.history/v-pre-seed-nav.*.
Sidebar (v68 추가)
2026-10-04 다시 정했다 — Side Navigation(
specs/components/side-navigation.md— 240 · 접힘 56 · 머리 64 · 항목 44). 위 "화면 틀 · 이동" 절. 옛 스펙은specs/components/sidebar.history/v-pre-seed-nav.*.
Navigation Menu (v68 추가)
2026-10-04 걷었다 — 데스크톱 머리의 메가 메뉴는 두 제품 모두 쓰는 곳이 없다(화면 틀 · 이동 추가 결정). 접힌 사이드바의 하위 펼침 메뉴는 Side Navigation 안에서 Menu 모양으로 정한다. 옛 스펙은
specs/components/navigation-menu.history/v-pre-seed-nav.*.
Menubar (v68 추가)
2026-10-02 걷었다 — 세 제품 모두 쓰는 곳이 없다(메뉴 · 툴팁 결정 6). 옛 스펙은
specs/components/menubar.history/v-pre-seed-menu.*. 줄 · 화면의 동작은 "메뉴 · 메뉴 시트 · 도움말 말풍선 · 툴팁" 절.
Command (Cmd+K menu, v68 추가)
2026-10-15 걷었다 — 세 제품 모두 ⌘K 팔레트를 쓰지 않는다(Desk 웹 팔레트는 2026-09-01 에 지웠다). cmdk 는 고르기 칸 두 곳의 검색 목록으로만 남아 있었다 — Desk 카드 상품 고르기(쓰는 곳 없음)는 지우고, HR 역할 고르기는 Select Box 여럿 고르기(
CheckSelectBox— 이름 + 역할 설명) + 아래 "저장" 한 번으로 바꾼다(마무리 10A — 폰 · 데스크톱 같은 모양, 아래 "마무리" 절 ·specs/components/select-box.md). 옛 스펙은specs/components/command.history/v-pre-drop.*. 검색해 고르는 긴 목록은 Input Button + Searchable List.
HR / Desk 듀얼 브랜드 (v68 5종 공통)
spec brand-neutral. 사이드바 · 머리 메뉴는 2026-10-04 "화면 틀 · 이동" 절로 옮겼다(Menubar 는 2026-10-02 걷었다).
Combobox (v69 추가)
2026-10-15 걷었다 — 칸에 바로 치는 콤보박스를 두지 않는다. 짧은 선택지는 Select, 검색해 고르는 긴 목록은 Input Button 이 여는 Searchable List 다(SEED 도 Combobox 를 두지 않는다 — Select 문서). 쓰는 곳 없는 카탈로그 항목만 남아 있었다.
Slider (v69 추가)
2026-10-09 다시 정했다 — 위 "입력" 절과
specs/components/slider.md(SEED Slider). 옛 브랜드 채움 · 흰 손잡이 16 + 브랜드 테두리 · 그림자 · 손잡이 위 · 옆 라벨 · 5 / 10 단위 가는 눈금 · 세로 슬라이더 · 호버 1.1배 · 불투명도 막힘 · PageUp ±10% 는 걷었다. 옛 스펙은specs/components/slider.history/v-pre-seed-input.*.
Toggle (v69 추가)
2026-10-09 다시 정했다 — 켜고 끄는 아이콘 단추 하나(위 "입력" 절과
specs/components/toggle.md). 글 · 아이콘 + 글 변형, 켬의 바탕 · 테두리, 불투명도 막힘은 걷었다 — 거르기는 Chip, 설정은 Switch 이고 서식 툴바는 쓰는 곳이 없다. 옛 스펙은specs/components/toggle.history/v-pre-seed-input.*.
Toggle Group (v69 추가)
2026-10-09 걷었다 — 하나 고르기 2 ~ 4칸은 Segmented Control, 여럿 · 짧은 폼 값은 Chip, 5개 이상은 Select 다(위 "입력" 절). 옛 스펙은
specs/components/toggle-group.history/v-pre-seed-input.*.
Input OTP (v69 추가)
2026-10-09 다시 정했다 — Input 한 칸(위 "입력" 절과
specs/components/input-otp.md). 칸마다 입력 · 6칸 · 3-3 구분 · 자동 다음 칸은 걷었다 — 칸을 나누지 않는다(SEED Text Input). 옛 스펙은specs/components/input-otp.history/v-pre-seed-input.*.
HR / Desk 듀얼 브랜드 (v69 5종 공통)
spec brand-neutral. Slider · Toggle · Input OTP 의 쓰는 자리는 2026-10-09 "입력 — HR" · "입력 — Desk" 절로 옮겼다(Toggle Group 은 걷었다).
Accordion (v70 추가)
2026-10-10 다시 정했다 — 위 "펼치고 접기 · 나누기" 절과
specs/components/accordion.md(SEED Accordion). 옛 single 기본 · 트리거surface-default바탕 + 1px 테두리 · 호버 바탕 · 펼침 200ms + 투명도 · 꺾쇠 150ms · 모션 줄이기면 즉시 · 펼친 내용region은 걷었다 — 늘 여럿 + 모두 펼치기, 펼침은 300ms · 줄이기면 150ms 서서히. 옛 스펙은specs/components/accordion.history/v-pre-seed-collapse.*.
Collapsible (v70 추가)
2026-10-10 다시 정했다 — 트리거는 Accordion 항목 하나의 모양(위 "펼치고 접기 · 나누기" 절과
specs/components/collapsible.md). 옛 글 · 아이콘 + 글 트리거 · "자세히" · 긴 코드 접기 쓰임 · 펼친 내용region은 걷었다 — 잘린 글은 펼치지 않고 자르지 않는다. 옛 스펙은specs/components/collapsible.history/v-pre-seed-collapse.md.
Hover Card (v70 추가)
2026-10-02 걷었다 — 쓰는 곳이 없다(메뉴 · 툴팁 결정 6). 옛 스펙은
specs/components/hover-card.history/v-pre-seed-menu.*. 짧은 설명은 Tooltip · Help Bubble, 버튼이 있는 내용은 Popover.
Context Menu (v70 추가)
2026-10-02 걷었다 — 쓰는 곳이 없다(메뉴 · 툴팁 결정 6). 옛 스펙은
specs/components/context-menu.history/v-pre-seed-menu.*. 우클릭 · 길게 누르기로만 열리는 메뉴는 두지 않는다 — 줄의 동작은 줄을 눌러 들어간 화면에(여럿이면 머리 ⋮, 표 줄은 줄 끝 ⋮ — 2026-10-25).
Alert Dialog (v70 추가)
2026-10-02 SEED Alert Dialog 로 다시 정했다 — 위 "시트 · 대화상자 · 확인창 · 팝오버" 절과
specs/components/alert-dialog.md를 따른다.
Table
2026-10-08 — 원본은
specs/components/table.md·table.yaml(SEED 문서 표 · 디자인 그림). 옛 Table · Data Table(v71)을 합쳤다 — 회색 대문자 머리 · 머리 바탕 · 줄무늬 · compact · 고른 줄 브랜드 8% + 왼쪽 선 · 칸 사이 화살표 이동 · 열 크기 조절 · 열 순서 바꾸기는 걷었다.
| 자리 | 값 |
|---|---|
| 머리 줄 | 41 — 위아래 10 · 좌우 16 · 14 / 20 · 500 · fg-neutral, 바탕 없음 |
| 본문 줄 | 45 — 위아래 12 · 좌우 16 · 14 / 20 · 400. 썸네일 · 두 줄 칸이 있으면 72 |
| 줄 선 | 1px stroke-neutral-subtle — 마지막 줄까지, 세로 선 · 줄무늬 없음 |
| 숫자 열 | 오른쪽 + 고정폭 숫자(머리도), 고정폭 글꼴 없음 · 돈은 원까지 · 빼기 U+2212 |
| 정렬 | 머리 칸 전체가 버튼 · ↑↓ 늘 보임(fg-neutral-muted, 지금 방향만 fg-neutral) · aria-sort · 누를 때마다 내림 ↔ 오름 두 단계(숫자 · 날짜 열은 처음 내림) |
| 줄 동작 | 줄 끝 ⋮(보이는 40 · 누르는 44 · "{줄} 더보기", 머리 글 없음) · 줄을 누르면 상세 |
| 선택 | 첫 열 Checkbox 24 · 고른 줄은 바탕 없이 체크로만 · 고른 줄이 있으면 표 위 일괄 작업 바(브랜드 파일의 brand-weak 역할 색 한 값 · 48 · 모서리 12). 바 안 동작은 모두 ghost neutral — 지우기의 빨강은 확인창에서(2026-10-17 01T-033 A) |
| 768 미만 | List 줄 — 첫 열은 제목, 다음 열 1 ~ 2개는 설명, 핵심 숫자 · 상태는 오른쪽 값, 나머지는 상세. 넘김은 끝없이 불러오기 |
| 빈 · 실패 · 로딩 | 머리는 그리고 본문 자리에 줄 스켈레톤 · Result Section medium(실패는 다시 시도) |
| 의미 | <table> · <caption> · <th scope> · aria-sort — 표처럼 보이는 div 격자를 두지 않는다 |
| 넘김 | 표 아래 Table Pagination — 표 아래 12 는 넘김 줄이 갖고, 표의 넘김 줄 자리는 좌우 24 만(2026-10-17 03-D 결정 5 B) |
Data Table (v71 추가)
2026-10-08 걷었다 — 위 Table 절과
specs/components/table.md로 합쳤다(정렬 · 선택 · 일괄 작업 · 머리 고정 · 넘김). 열 거르기 · 표 위 검색 · 열 보이기 바꾸기 · 내보내기 줄은 이번에 정하지 않았다.
Carousel (v71 추가)
2026-10-04 걷었다 — 세 제품에 쓰는 곳이 0이고 SEED 에도 캐러셀 컴포넌트가 없다(사용자 결정 — 이미지 비교 7A). 그림 여러 장은 끝이 보이는 가로 줄(Scroll Fog
row)에 Image Frame 을 잇고, 장수는 Indicator 글("1 / 12" · "+9")로 알린다 — "이미지 — Image Frame · Aspect Ratio · Logo Tile" 절. 점 지시자 · 화살표 · 자동 넘김은 두지 않는다. 옛 스펙은specs/components/carousel.history/v-pre-seed-image.*.
Scroll Area (v71 추가)
2026-10-10 다시 정했다 — 기본 스크롤 + 전역 스크롤바 한 벌(위 "펼치고 접기 · 나누기" 절과
specs/components/scroll-area.md). 옛 always-visible · hover · scrolling 변형 · 6 ~ 8px ·surface-input바탕 · 불투명도 0.4 ~ 1 · "필요 시 이름" 은 걷었다 — 6px 알약 · Firefox 두 줄은@supports not selector(::-webkit-scrollbar)안 · 초점 가는 것이 없는 상자는tabindex="0"+ 이름. 옛 스펙은specs/components/scroll-area.history/v-pre-seed-collapse.*.
Resizable (v71 추가)
2026-10-10 다시 정했다 — HR 관리 화면 나누기 · 대시보드 위젯 크기(위 "펼치고 접기 · 나누기" 절과
specs/components/resizable.md). 옛 손잡이 4 ~ 6px · hover 브랜드 색 · 세로 · 중첩 · snap 25 / 50 / 75% · ±1% ·Enter·Space로 접기 · "localStorage 권장" 은 걷었다 — 선 1px + 손잡이 표시 · 누르는 폭 16 · 5% · 목록 20 ~ 40% · 화면마다 기억 · 한 번 누르면 25 ↔ 40. 옛 스펙은specs/components/resizable.history/v-pre-seed-collapse.*.
HR / Desk 듀얼 브랜드 (v71 5종 공통)
spec brand-neutral. Scroll Area · Resizable 의 쓰는 자리는 2026-10-10 "펼치고 접기 · 나누기 — HR" · "— Desk" 절로 옮겼다. Table · Data Table 은 2026-10-08 Table 절로 합쳤고, Carousel 은 2026-10-04 걷었다.
Sonner (v72 추가, Toast 강화)
2026-10-02 걷었다 — Snackbar 로 바꿨다("알림 메시지 — Snackbar · Callout · Page Banner · Result Section" 절). 옛 스펙은
specs/components/sonner.history/v-pre-seed-feedback.*.
Aspect Ratio (v72 추가)
2026-10-04 SEED Aspect Ratio 로 다시 정했다 — "이미지 — Image Frame · Aspect Ratio · Logo Tile" 절과
specs/components/aspect-ratio.md. 그림이 아닌 자리(동영상 · 지도)의 비율 상자이고, 비율은 Image Frame 과 같은 여덟 가지다(기본 4:3 — 옛 16:9 기본 · 3:2 · 21:9 · 9:16 을 걷었다). 그림은 Image Frame 이다. 옛 스펙은specs/components/aspect-ratio.history/v-pre-seed-image.*.
Chart
2026-10-08 — 원본은
specs/components/chart.md·chart.yaml. 색은 Colors 의 v110 · v111 이다. 옛 v72 의 아래 범례 · hover card 툴팁 · 16:9 · 데이터 점마다tabindex는 걷었다.
| 자리 | 값 |
|---|---|
| 색 | 차트 10색 — 라이트 700 · 다크 800-dark. 저장된 색 먼저, 색이 없는 항목은 그 차트에서 아직 쓰지 않은 색부터 배정 순서로. 회색은 "기타" 전용 |
| 눈금 글자 | 11 / 15(text-t1) · fg-neutral-subtle · 고정폭 숫자 — 이중 축이면 그 계열의 색. 돈 축만 "만" 으로 줄인다 |
| 격자 | 가로 점선(3 · 3) stroke-neutral-subtle 만 — 세로 격자 · 축 선 없음 |
| 이중 축 | 크기가 열 배 넘게 다른 두 계열(수입 · 지출) — 왼쪽 · 오른쪽 눈금 |
| 툴팁 | 떠 있는 표면 bg-layer-floating · shadow-s3 · 모서리 12 — 머리 12 · fg-neutral-subtle, 줄 "■ 라벨 값"(값 700 · 원까지) |
| 선 · 막대 범례 | 차트 위 지표 타일(점 + 이름 + 합계, 켠 계열 바탕 chart-{색}-subtle) — 누르면 계열을 켜고 끈다 |
| 도넛 범례 | 카테고리 목록(색 네모 + 이름 + % + 금액 "원") · 가운데 합계도 원까지 |
| 열지도 | 칸 정사각형 · 모서리 4 · 사이 6, 세기 다섯(브랜드 채움 18 ~ 100%) — 칸 폭 112 이상에서만 금액을 원까지(11 · 700), 좁으면 세기 색만 · 값은 툴팁 · 표로 보기 |
| 가로축 | 오늘에서 끝난다 — 오늘 뒤 날짜를 0 으로 그리지 않는다 |
| 빈 · 실패 · 로딩 | 차트 자리 Skeleton(모서리 16) · Result Section medium(실패는 다시 시도) |
| 보조 기술 | 차트 상자 role="img" + 요약 이름 · 범례 목록이 대체 · "표로 보기" · 모션 줄이기면 바로 그린다 |
Date Range Picker (v72 추가)
2026-10-03 걷었다 — 기간은 Date Picker 기간("날짜 · 시각 고르기" 절)이다. 칸 하나 · 달력 하나, 빠른 기간은 한 벌(옛 "오늘 / 어제 / 지난 7일 …" + "취소 · 적용" 을 대신).
Time Picker (v72 추가)
2026-10-03 걷었다 — 시각은 Time Picker("날짜 · 시각 고르기" 절 ·
specs/components/time-picker.md)다. 치는 칸 · 24시간("14:30")을 오전·오후 12시간 휠로 바꿨다.
HR / Desk 듀얼 브랜드 (v72 5종 공통)
spec brand-neutral. brand 파일 — HR(Sonner top-right 결재 알림 stack / Chart bar/line dashboard / Date Range Picker dual desktop / Time Picker 결재 일정 5분 step), Desk(Sonner bottom-center 모바일 / Chart pie 가계부 카테고리 / Aspect Ratio 16:9 메모 attachment / Date Range Picker single 모바일).
Banner (v73 추가)
2026-10-02 걷었다 — 화면 안 안내는 Callout, 페이지 맨 위 띠는 Page Banner 다("알림 메시지 — Snackbar · Callout · Page Banner · Result Section" 절).
Chip
수치 · 규칙의 원본은 specs/components/chip.md · chip.yaml 이다 — 2026-10-02 SEED Chip 구조로 새로 정했다(옛 v73 Tag / Chip 을 대신한다). 고르거나 넣은 값을 보이는 작은 알약이고, 누를 수 없는 표시(상태 · 분류 · 메타)는 Badge · Tag Group 이다(위 "Badge · Notification Badge · Tag Group" 절). 이 절은 토큰과 닿는 자리만 모은다.
쓰임
| 쓰임 | 의미 | 고른 모습 |
|---|---|---|
| 고르기 — 하나(2 ~ 4개 짧은 폼 값 · 거르기의 한 축) | 라디오 — 다시 눌러도 풀리지 않는다, "전체" 는 맨 앞 선택지 | 있다 |
| 고르기 — 여럿 | 체크박스 — 다시 누르면 풀린다, "전체 선택" 칩은 두지 않는다 | 있다 |
| 제안(빠른 금액 · 빠른 기간 · 프리셋) | 버튼 — 누르면 칸에 값을 넣는다 | 없다 |
| 필터 바(목록 위, 조건마다 칩 · 뒤 아래 화살표) | 버튼 — 그 조건만 시트 · 팝오버로 연다 | 걸린 조건은 짙은 채움 + 값 요약("식비 외 2개") |
| 입력값 | 글 + "{글} 지우기" 버튼 | Outline Weak 고른 모습 |
모양과 색
| 요소 | 값 |
|---|---|
| 크기 | small 32 · medium 36(기본) · large 40, 모서리 radius-full, 글 t4 14 · 500(세 크기 같다), 좌우 12 · 14 · 16, 앞 아이콘 14 · 16 · 16 과 글 사이 6 |
| Solid | 안 고름 bg-neutral-weak-alpha(투명 — 회색 바닥 · 흰 표면 어디서나, v120) · 고름 bg-neutral-inverted + fg-neutral-inverted |
| Outline Strong | 안 고름 투명 + 안쪽 1px stroke-neutral-weak · 고름 bg-neutral-inverted(테두리 없음) |
| Outline Weak(기본) | 안 고름 투명 + 1px stroke-neutral-weak · 고름 bg-neutral-weak + 1px stroke-neutral-contrast(글자 그대로) |
| 누름 · 호버 | bg-neutral-weak-pressed · bg-layer-default-pressed · bg-neutral-inverted-pressed, 칩 전체 2px 거리 축소(v104) |
| 비활성 | bg-disabled · fg-disabled(흐림 없음 — v106). 고른 채 막히면 1px stroke-neutral-solid 를 남긴다 |
| 묶음 | 칩 사이 spacing-between-chips(8). 폼 · 시트 안은 줄바꿈(줄 사이 8), 목록 위 줄은 가로 스크롤(안쪽 여백 spacing-global-gutter) |
고른 칩은 브랜드 색이 아니라 중립색이다 — Desk · HR 이 같고, 고른 칩이 여럿 보여도 브랜드 버튼과 다투지 않는다(사용자 결정 2026-10-02).
쓰는 규칙
- 2 ~ 4개 짧은 폼 값은 Chip, 5개 이상은 Select, 글이 긴 2 ~ 4개는 Radio · Checkbox.
- 3상태 칩(고름 → 빼고 → 해제)은 두지 않는다 — 빼는 조건은 "고른 것만 · 고른 것 빼고" 를 먼저 고른다.
- 제안 칩은 고른 모습으로 남기지 않는다. 필터 바는 걸린 조건 칩의 글이 곧 조건이라 "필터 2" 같은 개수를 따로 두지 않는다.
- 칩 모양 탭(Tabs 의 Chip Tabs)과 필터 칩을 한 화면에 같은 모양으로 두지 않는다 — 탭을 Line 으로.
Accessibility 체크리스트
- 하나 고르기
radiogroup(화살표로 옮기면 고른다) · 여럿 체크박스 · 제안 · 여는 칩은 버튼(여는 칩aria-haspopup="dialog") —aria-pressed는 쓰지 않는다 - 묶음 이름은 Field 라벨 ·
aria-label, 아이콘만 있는 칩은aria-label - 키보드 포커스에만 링 2px · 띄움 2px, 누르는 영역은 가로 · 세로 44 까지(아이콘만 있는 칩도)
- 입력값 지우기 이름 "{글} 지우기", 지운 뒤 포커스는 다음 칩
Popover (v73 추가)
2026-10-02 SEED Popover 로 다시 정했다 — 위 "시트 · 대화상자 · 확인창 · 팝오버" 절과
specs/components/popover.md를 따른다.
File Upload (v73 추가)
2026-10-15 걷었다 — 사진 · 파일을 붙이는 칸은 Attachment Input(
specs/components/attachment-input.md— SEED, 위 "마무리" 절)이다. 옛 2px 점선 상자 · 회색 바탕 · 📁 · 끌기 때 브랜드 테두리 + 8% 바탕 · 막힘 불투명도 0.5 · 성공 ✓ 글은 걷었다 — 드롭존은 1px 실선stroke-neutral-solid(끌기stroke-neutral-contrast+bg-layer-default-pressed)이고, 올리는 중은 값 있는 원 24, 실패는 "다시 시도" 다.
Treeview (v73 추가)
2026-10-10 다시 정했다 — 여러 단계에서 고르는 나무는 Tree View(APG Treeview —
specs/components/tree-view.md, HR 부서), 하위 줄을 접는 카테고리는 List 하위 줄(specs/components/list.md)이다(위 "펼치고 접기 · 나누기" 절). 옛 고름surface-input+ 왼쪽 브랜드 2px · 여럿 고르기 · 끌어서 옮기기 · 안내 선 · 메모 폴더 나무는 걷었다.
HR / Desk 듀얼 브랜드 (v73 5종 공통)
spec brand-neutral. brand 파일 — HR(Banner 약관 변경 / Chip 결재라인 입력값 칩 / Popover 결재 의견 입력), Desk(Banner 시스템 점검 / Chip 메모 태그 입력값 칩 / Popover 카테고리 quick edit). 나무의 쓰는 자리는 2026-10-10 "펼치고 접기 · 나누기 — HR" · "— Desk" 절로, 첨부의 쓰는 자리는 2026-10-15 "마무리 — HR" · "— Desk" 절로 옮겼다.
Z-Index Layers
Groo 의 floating layer stacking 정책. 시스템 wide 가이드. 각 컴포넌트의 z-index 는 이 표의 층을 따르고, 층마다 값은 DESIGN.md 의 z-index 토큰(v116)이 원본이다.
Accordion
관련 정보를 세로로 묶어 두고 항목마다 머리를 눌러 상세를 펼치는 목록 — 카드 혜택 · 유의사항처럼 상세가 길어 다 펼쳐 두면 화면이 몇 배로 길어지는 자리에 쓴다. 하나만 접고 펴는 자리는 Collapsible, 단계가 있는 고르는 나무는 Tree View, 하위 줄을 접는 목록은 List 의 하위 줄이다.