디자인 시스템
Semantic Sync 토큰 (Figma 1:1 + shadcn 표준 호환)
색상
Atomic 팔레트(전체 스케일) → Semantic 토큰(컴포넌트 실사용) 2단계 구조. 파란 숫자 = Semantic 연결 스텝.
전체 팔레트
컴포넌트에서 직접 사용 금지 — 시맨틱 토큰을 통해서만 참조Cool Neutral
클릭하면 CSS 변수명 복사 (예: --cool-neutral-500) · 파란 숫자 = 시맨틱 토큰 연결
Blue
클릭하면 CSS 변수명 복사 (예: --blue-500) · 파란 숫자 = 시맨틱 토큰 연결
Violet
클릭하면 CSS 변수명 복사 (예: --violet-500) · 파란 숫자 = 시맨틱 토큰 연결
Red
클릭하면 CSS 변수명 복사 (예: --red-500) · 파란 숫자 = 시맨틱 토큰 연결
Green
클릭하면 CSS 변수명 복사 (예: --green-500) · 파란 숫자 = 시맨틱 토큰 연결
Amber
클릭하면 CSS 변수명 복사 (예: --amber-500) · 파란 숫자 = 시맨틱 토큰 연결
시맨틱 토큰
클릭하면 Tailwind 클래스명 복사bg-primary--primary·#3182f6·메인 액션 버튼 · 강조 배경↑ 컬럼 구조 예시 (실제 토큰 카드 구조와 동일) · 토큰 카드 클릭 시 클래스명 복사
Background
Fill
Text
Brand
Border
Alpha (overlay · divider)
Status
타이포그래피
font-size
Tailwind: font-size-10 ~ font-size-36font-size-10font-size-12font-size-13font-size-14font-size-16font-size-18font-size-20font-size-22font-size-24font-size-28font-size-34font-size-36font-weight
Tailwind: font-weight-normal / font-weight-medium / font-weight-semiboldfont-weight-normalfont-weight-mediumfont-weight-semiboldfont_letter_spacing
Tailwind: font_letter_spacing-0 / font_letter_spacing-050 / font_letter_spacing-100font_letter_spacing-00shadcn 기본 — 이 프로젝트에서 거의 미사용font_letter_spacing-050-0.5pxcomposite 토큰 기본값 — 대부분의 UI 텍스트font_letter_spacing-100-1px긴 본문 가독성용line-height
Tailwind: line-height-120 ~ line-height-160Bonydak Planner
line-height-1201.2제목류 — 헤딩, 강조 숫자Bonydak Planner
line-height-1301.3서브타이틀Bonydak Planner
line-height-1401.4버튼, 배지, 짧은 레이블Bonydak Planner
line-height-1601.6본문 — composite 토큰 기본 행간Semantic 타이포 토큰
font-size / line-height / font-weight / letter-spacing 하나로 묶인 Semantic 클래스 — text-h* / text-body* / text-captiontext-h3-bold24px / semibold / lh 36px / ls -0.5px
재배정 타입 설정 — 상담 관리
text-h422px / semibold / lh 32px / ls -0.5px
배정 완료 DB
text-h5-bold20px / semibold / lh 30px / ls -0.5px
설계사 검색
text-body3-bold14px / semibold / lh 22px / ls -0.5px
이민혁 · 010-1111-1111 · 2026.01.01
text-body3-medium14px / medium / lh 22px / ls -0.5px
이민혁 · 010-1111-1111 · 2026.01.01
text-body3-normal14px / regular / lh 22px / ls -0.5px
이민혁 · 010-1111-1111 · 2026.01.01
text-body4-bold13px / semibold / lh 20px / ls -0.5px
정상 · 계약 예정 · 상담 종료
text-body4-medium13px / medium / lh 18px / ls -0.5px
정상 · 계약 예정 · 상담 종료
text-body4-normal13px / regular / lh 18px / ls -0.5px
정상 · 계약 예정 · 상담 종료
text-body5-bold12px / semibold / lh 20px / ls -0.5px
담당 설계사 · 상태
text-body5-medium12px / medium / lh 16px / ls -0.5px
담당 설계사 · 상태
text-body5-normal12px / regular / lh 16px / ls -0.5px
담당 설계사 · 상태
text-caption10px / regular / lh 16px / ls -0.5px
레이블 · 구분
라운드
토큰 시각화
rounded-sm2px
rounded4px
rounded-md6px
rounded-lg8px
rounded-fullpill
사용 계층 규칙
| 레벨 | 클래스 | 설명 |
|---|---|---|
| 카드 · 컨테이너 | rounded-lg | 8px — 가장 많이 사용 |
| 버튼 (default/sm) | rounded-lg | 8px |
| 필터 컨트롤 · 작은 버튼 | rounded-md | 6px — h-8/h-6 컨트롤 |
| 체크박스 · 미세 라운드 | rounded-sm | 2px |
| pill · 원형 (avatar/dot) | rounded-full | 9999px |
| ❌ 금지 | rounded-xl | 12px+ 라운드 사용 금지 |
Border
보더 굵기
border-border050.5px
특수 케이스 — 얇은 구분이 필요한 경우
border1px
기본값 — Tailwind 표준 (border-border10 동일)
보더 색상
border-subtle / border-border / border-primaryborder-subtle#e5e8eb카드·컨테이너 기본 보더 (cool-neutral-200)
border-border#d1d6dbshadcn 호환 보더 (cool-neutral-300)
border-primary#3182f6선택·포커스 상태
Shadow
그림자 스케일
shadow-xs필터 컨트롤 · 소형 팝업
shadow-sm카드 팝업 · select
shadow-md모달 · 사이드바
shadow-lg대형 팝오버
shadow-xl드래그 중 카드
스페이싱
토큰 스케일
Tailwind 네이티브 4px 그리드. 1 = 4px / 2 = 8px / 4 = 16px / 6 = 24px ...4px
18px
212px
316px
420px
524px
632px
840px
1060px
15사용 패턴
Tailwind 네이티브 4px 그리드 — prefix(p / m / gap / px / pt 등)는 상황에 따라 자유 조합| px | Tailwind 키 | 사용 패턴 |
|---|---|---|
| 4 | 1 | 아이콘 ↔ 텍스트 인라인 간격 |
| 8 | 2 | 타이트한 인라인 gap |
| 12 | 3 | 배지 padding · BusinessTree ↔ 본문 gap |
| 16 | 4 | 카드 간 gap · 필터 ↔ 테이블 mb |
| 20 | 5 | 카드 내부 세로 패딩 (py) |
| 24 | 6 | 페이지·카드 수평 패딩 (px) |
| 32 | 8 | 섹션 간 gap |
| 40 | 10 | 페이지 타이틀 상단 패딩 (pt) |
| 60 | 15 | 콘텐츠 하단 패딩 (pb-15) |
토큰 선택 가이드
어떤 색·간격·라운드를 쓸지 헷갈릴 때. 위에서부터 질문에 답하면 정답이 나오도록 설계.
색상 — 무엇을 표현하나?
컴포넌트에서 색을 결정할 때 따라가는 흐름브랜드 액션인가? (저장/확인/메인 CTA) → bg-primary / text-primary
상태 표현인가? → 성공 tint-success · 경고 tint-warning · 오류 tint-danger · 정보 tint-blue · 중립 tint-muted
면적이 큰 배경인가? (페이지·카드·모달) → bg-canvas-* (primary=흰 / tertiary=페이지 / quaternary=섹션)
작은 컴포넌트 배경인가? (배지·필 / 컨트롤 hover) → bg-fill-* (subtle=hover / strong=강조)
텍스트인가? → text-content-* (primary 진함 → assistive 옅음 → disabled 회색). 진함과 옅음 사이가 모호하면 한 단계 진한 쪽 선택.
오버레이/구분선인가? → 행 hover bg-alpha-black-02 / 셀 보더 border-divider-subtle
간격 / 라운드 / 굵기
px 단위로 선택하지 말고 의미로 선택간격 (gap / padding)
- 아이콘↔텍스트 →
gap-s4(4px) - 인라인 →
gap-s8(8px) - 카드↔카드 →
gap-s16(16px) - 섹션 간 →
gap-s32(32px)
라운드
- 카드·컨테이너 →
rounded-lg(8px) - 필터·버튼(sm/xs) →
rounded-md(6px) - 체크박스 →
rounded-sm(2px) - pill·avatar →
rounded-full
굵기 (font-weight)
- 본문 →
font-normal(400) - 레이블 →
font-medium(500) - 제목·강조 →
font-semibold(600) font-bold사용 금지
네이밍 규칙
토큰 이름은 의미로 읽힌다. Prefix가 카테고리, Suffix가 위계.
Prefix — 무엇을 다루는 토큰인가
| Prefix | 예시 | 의미 |
|---|---|---|
bg-canvas-* | bg-canvas-primary | 면적 큰 배경 (페이지·카드·모달) |
bg-fill-* | bg-fill-subtle | 작은 컴포넌트 배경 (배지·hover) |
bg-primary-* | bg-primary-subtle | 브랜드 강조 배경 |
bg-{color}-tint | bg-green-tint | 상태 색 tint 배경 |
bg-alpha-* | bg-alpha-black-02 | 투명 오버레이 (반투명 hover/딤) |
text-content-* | text-content-primary | 일반 텍스트 색 (위계별) |
text-inverse-* | text-inverse-primary | 반전 텍스트 (브랜드 위 흰글자) |
text-{color}-tint | text-green-tint | 상태 색 tint 텍스트 (배지 안) |
border-* | border-subtle | 보더 색·굵기 |
border-divider-* | border-divider-subtle | 셀·구분선 (alpha 기반) |
Suffix — 위계와 상태
위계 (진함 → 옅음)
primary → secondary → tertiary → quaternary → assistive → disabled진할수록 강조, 옅을수록 보조
상태
-hover · -pressed · -subtle · -strong · -inverseinteraction과 강조도 표현
❌ 금지 패턴
이런 패턴은 사용 금지 — 빌드 통과해도 디자인 시스템 위반bg-blue-500같은 raw atomic 토큰 직접 사용 — 반드시 semantic을 거쳐서 (예:bg-primary)dark:bg-canvas-primary— 다크모드 미지원. 모든 dark: prefix 금지rounded-xl이상 — Vega 스타일 상한선. 카드는 rounded-lg(8px)까지font-bold— atomicfont-weight-bold로만 허용. 일반은 font-semiboldbg-primary/10같은 alpha modifier — semantic 토큰엔 금지.bg-primary-subtle같은 named 토큰 사용gap-0.5,gap-1.5같은 half-step 간격 — 4px 그리드 벗어남. s-token 사용
Tailwind 매핑표
Figma 토큰 ↔ shadcn 표준 ↔ 우리 Tailwind 클래스. 한눈에 보고 골라 쓰는 치트시트.
Background
| Tailwind 클래스 | CSS 변수 | Figma 토큰 | 언제 쓰나 |
|---|---|---|---|
bg-canvas-primary | --bg-primary | bg_primary | 카드·모달 흰 배경 |
bg-canvas-secondary | --bg-secondary | bg_secondary | 오프화이트 영역 (드물게) |
bg-canvas-secondary | --bg-tertiary | bg_tertiary | 페이지 기본 배경 (모든 페이지) |
bg-canvas-quaternary | --bg-subtle | bg_subtle | 섹션 구분·테이블 짝수행 |
bg-primary | --primary | (shadcn 표준) | 메인 액션 버튼 (브랜드 블루) |
bg-primary-subtle | --primary-subtle | (파생) | 사이드바·트리 선택 배경 |
bg-fill-subtle | --fill-subtle | (파생) | 테이블 헤더·작은 컴포넌트 hover |
Text · Border
| Tailwind 클래스 | CSS 변수 | Figma 토큰 | 언제 쓰나 |
|---|---|---|---|
text-content-primary | --text-primary | text_primary | 제목·강조 (#191F28) |
text-content-secondary | --text-secondary | text_secondary | 본문 (cool-neutral-900) |
text-content-tertiary | --text-tertiary | text_tertiary | 서브 텍스트 (cool-neutral-700) |
text-content-assistive | --text-assistive | text_assistive | placeholder·힌트 (#8B95A1) |
text-primary | --primary | (shadcn 표준) | 링크·브랜드 텍스트 |
text-inverse-primary | --common-100 | text_inverse_primary | 브랜드 버튼 위 흰 글자 |
border-subtle | --border-subtle | border_subtle | 카드 보더 (cool-neutral-200) |
border-border | --border | border_primary | shadcn 표준 보더 |
border-divider-subtle | --divider-subtle | (파생) | 테이블 셀 행 라인 (alpha-blue 4%) |
브랜드 커스터마이징
B2B 다중 테넌트 — --primary 한 줄만 바꾸면 모든 컴포넌트 자동 추종. 한 build로 여러 브랜드 지원.
1단계 — globals.css에 브랜드별 오버라이드 추가
/* :root 블록 끝부분에 추가 */
[data-brand="green"] {
--primary: var(--green-500); /* #03b26c */
}
[data-brand="orange"] {
--primary: oklch(0.65 0.20 45); /* 임의 hex/oklch도 가능 */
}2단계 — html 또는 페이지 wrapper에 data-brand 적용
정적 (테넌트 단위)
// app/layout.tsx
<html lang="ko" data-brand={tenant.brand}>
{/* "default" | "green" | "orange" */}
</html>동적 (런타임 변경)
useEffect(() => {
document.documentElement
.dataset.brand = currentTenant.brand
}, [currentTenant])자동 추종 컴포넌트 — 코드 수정 불필요
--primary 변경 시 다음이 모두 자동 추종 (CSS 변수 추상화):
예외 — 브랜드와 무관한 토큰
reference에서 정적 색이라 브랜드와 무관bg-blue-tint,text-blue-tint— info 배지용 파랑 (브랜드가 그린이어도 info=파랑)bg-success,bg-warning,bg-destructive— 시맨틱 상태색
내비게이션
앱 사이드바 + 상단 헤더 구조 목업. 실제 컴포넌트는 app-sidebar.tsx / header.tsx 참고.
사이드바
app-sidebar.tsx — collapsible icon 모드| 상태 | 클래스 |
|---|---|
| 활성 서브메뉴 | bg-primary-subtle text-primary font-semibold (= blue-50 #e8f3ff) |
| 비활성 서브메뉴 | text-content-quaternary hover:bg-alpha-black-05 |
| 그룹 트리거 (활성 자식) | text-content-quaternary — 아이콘만 활성 표시 |
| hover 오버레이 | bg-alpha-black-05 (5% 불투명 다크 오버레이) |
| 컨테이너 | w-[160px] bg-canvas-secondary border-r border-subtle |
헤더
header.tsx — h-12 / bg-canvas-secondary / border-b border-divider-normal페이지 콘텐츠
| 속성 | 값 |
|---|---|
| 높이 | h-12 (48px) |
| 배경 | bg-canvas-secondary |
| 하단 선 | border-b border-divider-normal |
| 좌측 영역 | 토글(w-16) + 보닥 플래너 + 구분선 + KB라이프 SVG |
| 우측 영역 | 세션 + 연장 Button + 구분선 + Avatar(h-7) |
| shadcn 컴포넌트 | useSidebar / Button / Avatar / AvatarFallback |
카드
기본 카드
카드 타이틀
bg-canvas-primary · rounded-lg · border-subtle
내부 구분선: mx-6 h-px bg-divider-subtle — 좌우 mx-6 인셋 필수
KPI 타일 카드
전체
승인대기
정상
일시제한
수직 구분선: absolute h-12 w-px bg-divider-normal
버튼
변형 × 크기 매트릭스
| variant | xs h-6 · 11px | sm h-8 | default h-9 | 설명 |
|---|---|---|---|---|
| primary | 메인 액션 — 저장 / 재배정 / 확인 | |||
| secondary | 보조 액션 — 필터 검색 (서브틀 브랜드) | |||
| outline | 약한 강조 — 취소 / 보조 옵션 | |||
| ghost | 투명 — 페이지네이션 / 아이콘 트리거 | |||
| neutral | 중립 액션 — 작업 영역 토글 | |||
| destructive | 위험 액션 — 삭제 / 회수 |
아이콘 + 텍스트 조합
아이콘은 버튼 텍스트 앞에 배치. data-[icon=inline-start] 자동 좌측 패딩 조정.
아이콘 버튼 사이즈
icon36px
shadcn 마이그레이션
| variant | bg / border | text | hover |
|---|---|---|---|
| primary | bg-primary | text-inverse-primary | bg-primary-hover |
| secondary | bg-primary-subtle | text-primary | bg-primary-subtle-hover |
| outline | border-border | text-content-primary | bg-canvas-quaternary |
| ghost | — | text-content-primary | bg-canvas-quaternary |
| neutral | bg-canvas-quaternary | text-content-primary | bg-fill-hover |
| destructive | bg-destructive-subtle | text-destructive | bg-destructive-subtle-hover |
border-ring ring-ring-glowdisabled → opacity-50 pointer-events-none| shadcn 기본 (설치 직후) | 이 프로젝트 (적용 후) | 변경 이유 |
|---|---|---|
bg-canvas-primary text-inverse-primary | bg-primary text-inverse-primary | primary SWAP — primary는 흰 배경이므로 brand action = accent |
hover:bg-primary (shadcn 서브틀 hover) | hover:bg-canvas-quaternary / hover:bg-muted | accent↔muted SWAP — shadcn accent는 우리 시스템에서 brand blue |
data-[state=checked]:bg-canvas-primary | data-[state=checked]:bg-primary | Checkbox ON 상태 — primary SWAP 동일 적용 |
필터
SearchFilter 라이브 데모
개별 컨트롤 패턴
Select — h-9 border-subtle bg-fill-filter
Input — variant='filter'
필터 초기화 (변경 시 노출)
컨트롤 공통: bg-fill-filter border-subtle shadow-none rounded-md h-9 · 초기화는 아이콘 버튼 금지 (텍스트 언더라인 버튼)
Input / Select 마이그레이션
Input
| shadcn 기본 (설치 직후) | 이 프로젝트 (적용 후) | 변경 이유 |
|---|---|---|
border-input (1px, border-border) | variant="filter" → border-subtle | 필터용 연한 보더 |
bg-transparent | variant="filter" → bg-fill-filter | 페이지 bg-canvas-secondary 위 대비 |
text-content-assistive (placeholder) | placeholder:text-content-assistive | assistive = 우리 시스템 placeholder 토큰 |
Select
| shadcn 기본 (설치 직후) | 이 프로젝트 (적용 후) | 변경 이유 |
|---|---|---|
bg-primary (shadcn 서브틀 hover) | hover:bg-blue-tint + border-info + text-primary | brand 컬러 명시적 hover — named atomic 참조 (alpha modifier 금지) |
bg-popover border-border (Content) | border-subtle className 추가 | 필터용 보더를 subtle로 오버라이드 |
bg-background (Trigger 기본) | bg-fill-filter className 추가 | 필터용 흰 배경 명시 |
필터 위치 패턴
패턴 A — 카드 헤더 내부
카드 타이틀
테이블
/ (홈) · /pending
패턴 B — 별도 카드 (mb-4)
테이블
/completed · /db/* · /management/*
테이블
| No. | 이름 | 휴대폰번호 | 소속 | 가입일 | 상태 |
|---|---|---|---|---|---|
| 1 | 이민혁 | 010-1111-1111 | 본사 > 사업단 1 > 지점 1 | 2026.01.01 | 정상 |
| 2 | 이민혁 | 010-1111-1111 | 본사 > 사업단 1 > 지점 1 | 2026.01.01 | 정상 |
| 3 | 이민혁 | 010-1111-1111 | 본사 > 사업단 1 > 지점 1 | 2026.01.01 | 정상 |
| 속성 | 값 | 비고 |
|---|---|---|
| TableHead 높이 | h-10 (40px) | 개별 파일 오버라이드 금지 |
| TableCell 높이 | h-[44px] | 터치 타겟 최소값 |
| TableCell 패딩 | px-3 py-2.5 | |
| No. 컬럼 | text-center | 헤더+셀 동일 |
| 나머지 컬럼 | text-left | 기본 |
| 숫자/날짜/전화 | num-cell | tabular-nums + tracking |
| 행 hover | hover:bg-alpha-black-02 | alpha 2% — 매우 미세, 텍스트 안 진해짐 |
| 선택 행 | data-[state=selected]:bg-blue-tint | blue-50 |
| 선택 행 hover | data-[state=selected]:hover:bg-primary-subtle-hover | blue-75 — 선택+hover 시 한 단계 진하게 |
배지
태그 배지 — 상태·분류 (tint 스타일)
tint-successgreen-50 bg / green-450 text — 활성 진행 (db-status: 진행중)tint-warningamber-50 bg / amber-700 text — 주의·대기 (현재 사용처 없음)tint-dangerred-50 bg / red-600 text — 명확한 부정 (completed: 상담 거절)tint-blueblue-50 bg / blue-700 text — 정보·신규 (db-status: 진행 예정)tint-mutedbg-canvas-quaternary / text-content-quaternary — 비활성·종결 (completed: 계약 완료, db-status: 종료)pill-* variants 제거 — tint-* (= tag) 스타일로 통일. 칸반 태그도 tint-* 사용.
기본 변형 (shadcn 표준)
shadcn 마이그레이션
| shadcn 기본 (설치 직후) | 이 프로젝트 (적용 후) | 변경 이유 |
|---|---|---|
bg-canvas-primary text-inverse-primary (default variant) | bg-primary text-inverse-primary | primary SWAP — brand badge = accent |
— | tint-* variants 추가 | 종결/분류용 배경 fill (badge-tint-* 전용 토큰) |
— | bg-badge-tint-success-bg / text-badge-tint-success-fg | 시맨틱 배지 색상 — globals.css에 전용 변수로 분리 |
bg-primary text-inverse-primary (shadcn secondary) | bg-canvas-secondary text-secondary-foreground | shadcn secondary = 우리 accent와 다른 값 |
페이지네이션
아무 번호나 눌러 7슬롯 고정 확인
| 컴포넌트 | 사용법 |
|---|---|
| PageNumbers | <PageNumbers totalPages={n} currentPage={p} onPageChange={setPage} /> |
| PageSizeSelect | <PageSizeSelect value={pageSize} onValueChange={(v) => { setPageSize(v); setCurrentPage(1) }} /> |
차트 팔레트
chart-1blue-500 · 주지표
chart-22순위
chart-33순위
chart-44순위
chart-5보조지표
chart-1 = blue-500 (#3182f6) · chart-2~5 = violet-500/550/600/650 · Area 차트 3선: chart-1 / chart-3 / chart-5 순서
레이아웃 패턴
패턴 1 — BusinessTree + 필터[별도] + 테이블
/completed · /db/assigned · /db/unassigned · /management/* · /organization/*Tree
필터 (mb-4)
테이블
<div className="flex gap-3 px-6 pb-15 items-start">
<BusinessTree />
<div className="flex-1 min-w-0">
<div className="mb-4"><XxxFilter /></div>
<XxxTable />
</div>
</div>패턴 2 — BusinessTree + 카드들
/ (홈) · /pendingTree
카드 1 (KPI/필터 내장)
카드 2
<div className="flex gap-3 px-6 pb-15 items-start">
<BusinessTree />
<div className="flex-1 min-w-0 flex flex-col gap-4">
{/* 카드들 */}
</div>
</div>패턴 3 — BusinessTree 없음 (전체 너비)
/db/status · 설정 페이지 (/settings/*)테이블 또는 설정 카드 (전체 너비)
<div className="px-6 pb-15"> <XxxTable /> </div>
현재 상태
이 시스템에 어떤 접근성 보호가 들어있고, 무엇이 빠져있는지 솔직하게.
자동 적용
shadcn / Radix 기본 — 의도하지 않아도 따라옴
- •
focus-visiblering (Button·Input·Select·Checkbox 등 26개) - • Modal·Dropdown focus trap
- • Pagination·Breadcrumb·Sidebar 내부 ARIA
- • Calendar·Combobox 키보드 네비
- • Tab·Enter·Esc 표준 키보드 동작
Baseline 적용
2026-05 — 커스텀 컴포넌트에 수동 추가
- • 아이콘 버튼
aria-label(5곳) - • 폼 컨트롤
aria-label(11곳: Search, Select, Combobox 등) - •
title툴팁 +aria-label병행
미적용 (백로그)
의도적으로 보류 — 별도 검토 필요
- • 커스텀 button·a 태그
focus-visible표준화 - • Tree
role/aria-expanded(BusinessTree·StructureTree·칸반) - • 색 대비 미달 토큰 사용처 교체
- • 키보드 단축키 / Tab 순서 표준
- •
prefers-reduced-motion대응
현재 등급: shadcn 기본만 의존하던 단계 → Baseline 단계로 진입. 스크린 리더 사용자에게 모든 인터랙티브 요소가 "이름"을 가짐. 키보드 전용 사용자에겐 일부 커스텀 트리·드래그 인터랙션이 여전히 미지원.
색 대비 매트릭스
WCAG 2.1 contrast ratio. 본문(<18px)은 AA 4.5:1 / AAA 7:1. 큰 글자(≥18px bold 또는 ≥24px)는 AA 3:1. 셀 클릭하면 비율 복사.
전체 매트릭스
text 토큰 × bg 토큰 — 실제 사용 가능한 조합 검증| text \ bg | bg-canvas-primary | bg-canvas-secondary | bg-canvas-tertiary | bg-canvas-quaternary | bg-primary | bg-primary-subtle |
|---|---|---|---|---|---|---|
Aa text-content-primary | 16.56AAA | 15.87AAA | 15.02AAA | 14.25AAA | 4.46AA-L | 14.74AAA |
Aa text-content-secondary | 11.00AAA | 10.53AAA | 9.97AAA | 9.46AAA | 2.96FAIL | 9.79AAA |
Aa text-content-tertiary | 7.11AAA | 6.81AA | 6.45AA | 6.12AA | 1.91FAIL | 6.33AA |
Aa text-content-quaternary | 4.62AA | 4.42AA-L | 4.19AA-L | 3.97AA-L | 1.24FAIL | 4.11AA-L |
Aa text-content-assistive | 3.04AA-L | 2.91FAIL | 2.76FAIL | 2.61FAIL | 1.22FAIL | 2.71FAIL |
Aa text-content-disabled | 2.01FAIL | 1.92FAIL | 1.82FAIL | 1.73FAIL | 1.85FAIL | 1.79FAIL |
Aa text-primary | 3.71AA-L | 3.56AA-L | 3.37AA-L | 3.20AA-L | 1.00FAIL | 3.31AA-L |
Aa text-inverse-primary | 1.00FAIL | 1.04FAIL | 1.10FAIL | 1.16FAIL | 3.71AA-L | 1.12FAIL |
주요 발견 — 의식적으로 인지해야 할 조합
text-primary on bg-canvas-primary = 3.71:1 — 모든 링크 텍스트가 본문 AA 미달. 14px 본문 링크는 시각적으로 잘 안 보일 수 있음. 링크는 가급적 underline 병행 권장.
text-inverse-primary on bg-primary = 3.71:1 — Primary 버튼의 흰 글자도 AA-Large만. 버튼 라벨이 14px+ 이고 font-medium 이상이라 실용상 OK지만 13px 이하 사용 금지.
text-content-assistive on bg-canvas-secondary (페이지 배경) = 2.91:1 — 페이지 배경 위에선 placeholder조차 미달. 흰 카드 안 placeholder는 OK (3.04:1 AA-L), 페이지 배경 위 본문은 절대 금지.
text-content-quaternary on bg-canvas-secondary = 4.42:1 — 본문 AA에 살짝 못 미침(4.5 기준 0.08 부족). 흰 카드 위(4.62:1)는 본문 OK. 페이지 배경 위에서는 text-content-tertiary 권장.
적용 패턴
새 컴포넌트·새 페이지 만들 때 따라야 할 규칙.
아이콘 버튼
아이콘만 있고 텍스트 없는 모든 button·a 태그 — 스크린 리더에 '이름'을 줘야 함<button onClick={openSidebar}>
<Menu className="h-4 w-4" />
</button><button onClick={openSidebar} aria-label="사이드바 열기">
<Menu className="h-4 w-4" />
</button>동적 상태(예: 펼침/접힘)는 라벨에 상태를 포함:aria-label={`${name} ${isOpen ? "접기" : "펼치기"}`}
폼 컨트롤
placeholder는 시각적 힌트일 뿐 — 스크린 리더의 라벨로 인정 안 됨<Input
placeholder="고객명 검색"
value={q}
onChange={...}
/><Input
placeholder="고객명 검색"
aria-label="고객명 검색"
value={q}
onChange={...}
/>Select·Combobox 트리거(button) 위에 시각적 라벨이 있으면 (예: "지역 · 서울"), aria-label="지역 선택" 추가. 동적 값은 aria-label={`지역 선택, 현재 선택: ${value}`} 처럼 상태 포함.
aria-hidden — 의미 없는 아이콘
스크린 리더가 무시 / 데코 아이콘에 적용{/* 텍스트 옆 보조 아이콘 — 라벨 중복 방지 */}
<Button>
<Search aria-hidden="true" />
검색
</Button>
{/* 구분 점 같은 데코 — 의미 없음 */}
<span aria-hidden="true">·</span>백로그
현재 미적용 항목 — 추후 별도 작업으로 검토.
| 항목 | 예상 임팩트 | 시각 변화 | 메모 |
|---|---|---|---|
| Focus ring 표준화 | 키보드 사용자 | Tab 시 + | 커스텀 button·a 태그에 focus-visible:ring-3 ring-ring-glow 일괄. shadcn 컴포넌트는 이미 적용됨. |
| Tree role/aria-expanded | 스크린 리더 | 없음 | BusinessTree·StructureTree·칸반에 role='tree'/role='treeitem'/aria-expanded. 키보드 화살표 핸들러 동시 작업 필요. |
| 색 대비 미달 사용처 정리 | 저시력 사용자 | 글자 톤 변화 | text-content-assistive를 본문으로 쓰는 곳을 tertiary로 교체. 디자이너 검토 후 진행. |
| 키보드 단축키 | 파워 유저 | 없음 | 테이블 행 ↑↓ 이동, 칸반 카드 이동, 사이드바 토글 단축키 등. |
| prefers-reduced-motion | 전정 민감 사용자 | 모션 비활성 | transition·animation을 미디어 쿼리로 끄기. globals.css에 한 줄로 추가 가능. |
| 스크린 리더 알림 (aria-live) | 스크린 리더 | 없음 | 필터 적용 후 결과 건수, 저장 완료 토스트 등 변화 알림. |
목표 등급
B2B 업무 툴 — WCAG 2.1 AA 본문 기준이 현실적 목표. 현재 Baseline 단계 → 백로그 6개 중 Focus ring · Tree role · 색 대비 정리 3개 마무리 시 본문 AA 도달. 나머지 3개(키보드 단축키 · reduced-motion · aria-live)는 사용자 피드백 기반으로 우선순위 결정.
shadcn 컴포넌트 현황
설치됨 (사용 중 / 설치 유지)
26개 · CLAUDE.md 기준button전체 액션 버튼
badge상태 배지
table모든 데이터 테이블
select필터 드롭다운
checkbox테이블 멀티선택
input검색 인풋
paginationPageNumbers / PageSizeSelect
sidebarlayout.tsx 사이드바
radio-group설정 3개 파일
popover날짜 선택, 멀티셀렉트
tabs대시보드 기간 탭
calendar날짜 범위 선택
dialog확인 모달
command설계사 검색 combobox
collapsible사이드바 메뉴
avatar사용자 아이콘
tooltip아이콘 설명
scroll-area커스텀 스크롤
breadcrumbsticky-breadcrumb.tsx
chart대시보드 차트
sheetsidebar.tsx 내부
skeletonsidebar.tsx 내부
separatorsidebar.tsx 내부
textareainput-group.tsx 내부
input-groupcommand.tsx 내부
toggle설치됨 (미사용)
제거됨 (필요 시 재설치)
18개 · npx shadcn@latest add [name] 으로 재추가accordionalertalert-dialogaspect-ratiobutton-groupcardcarouselcomboboxcontext-menudrawerdropdown-menulabelnavigation-menuresizableslidersonnerswitchtoggle-group새 컴포넌트 추가 후 필수 작업
npx shadcn@latest add [component]