개요
리바운드 비즈의 고객 페이지(채권자와 채무자가 실제로 쓰는 화면)를 만들 때 필요한 색·글자·컴포넌트 규칙이에요. 여기 적힌 값은 전부 rebound-biz 저장소에서 지금 돌고 있는 값이고, 새 화면은 이 값을 그대로 가져다 쓰면 됩니다.
이 문서를 쓰는 곳
| 제품 | 저장소 | 적용 |
|---|---|---|
| 리바운드 비즈 | GroundBasic/rebound-biz | 기준. 이 문서에 적힌 모든 값의 출처 |
| 채무자 페이지 | rebound-biz /debtor | 같은 토큰, 같은 컴포넌트 |
| 신규 고객 페이지 | — | 이 문서대로 시작 |
| 소개 페이지 | GroundBasic/rebound-info | 마케팅 톤은 별도, 브랜드 색만 공유 |
네 가지 원칙
| 원칙 | 뜻 |
|---|---|
| 데이터가 주인공 | 화면의 대부분은 무채색이에요. 색은 상태를 가리킬 때만 씁니다. 표 한가득 알록달록한 배지는 읽는 속도를 떨어뜨려요. |
| 채운 색은 하나 | 한 화면에서 #FF5900으로 채운 버튼은 하나. 나머지 행동은 흰 버튼이나 고스트로 내립니다. |
| 선보다 여백 | 카드는 테두리 없이 흰 배경 + 아주 옅은 그림자. 선은 표의 행 사이와 영역 경계에만. |
| 숫자는 줄을 맞춘다 | 금액·건수·날짜는 고정폭 숫자(tabular-nums), 금액 열은 오른쪽 정렬. |
문서의 구성
| 섹션 | 무엇이 있나 |
|---|---|
| Foundations | 팔레트 원본(Primitive)과 역할별 토큰(Semantic), 글자 스케일, 여백·모서리·그림자, 아이콘 |
| Components | 버튼·배지·입력·카드·표·모달·내비. 디자인 탭은 스펙과 규칙, 코드 탭은 실제 클래스 정의 |
| Patterns | 한 화면을 구성하는 순서, 빈 화면·로딩·오류, 화면에 쓰는 말 |
| Resources | 로고 파일, Tailwind 설정과 CSS 변수 |
설치와 사용
토큰 파일 두 개와 폰트 한 줄이면 준비가 끝나요. 새 저장소든, 이미 있는 페이지든 같습니다.
1. 설치
2. 토큰 가져오기
rebound-biz에서 두 파일을 그대로 복사합니다. 값은 Resources · 토큰에도 전문이 있어요.
| 파일 | 가져올 부분 |
|---|---|
| tailwind.config.js | theme.extend의 colors · fontFamily · boxShadow · borderRadius |
| src/index.css | @layer base(바탕·스크롤바·모바일 입력) + @layer components(버튼·입력·표·배지) |
3. 폰트
4. 화면 만들기 전 확인
| 확인 | 기준 |
|---|---|
| 색을 골랐나요 | hex가 아니라 Semantic 토큰의 역할로. 팔레트에 없는 색은 만들지 않아요 |
| 주 행동은 하나인가요 | 채운 오렌지 버튼은 화면에 하나 |
| 숫자 열은 오른쪽인가요 | 금액·비율은 오른쪽 정렬 + 고정폭 숫자 |
| 빈 화면이 있나요 | 데이터가 없을 때 무엇을 보여줄지 먼저 정하기 |
| 모바일에서 열리나요 | 640px 아래에서 입력 글자 16px, 표는 가로 스크롤 |
index.css 아래쪽에 있어요.Foundations
모든 화면의 바탕이 되는 가장 작은 단위들이에요. 색·글자·여백·아이콘처럼 컴포넌트를 만들기 전에 먼저 맞춰야 하는 기준을 모았습니다.
Base Material
Colors
색은 역할로 고릅니다. 화면을 만들 때는 hex가 아니라 Semantic 이름을 쓰고, 그 값의 출처인 팔레트는 Atomic에 있어요. 같은 오렌지라도 주 버튼에 쓸 때와 상태 표시에 쓸 때 이름이 다릅니다.
Typography
리바운드의 정보 위계와 읽기 흐름을 일관되게 만드는 타입 시스템입니다. Pretendard 한 벌, 굵기는 Bold와 Regular, 자간은 전부 -2.5%. 크기는 데스크톱·태블릿·모바일 세 단계로 줄어듭니다.
Font
한글과 라틴, 숫자를 한 서체로 맞출 수 있어서 Pretendard 하나만 씁니다.
Type scale
다섯 계열을 실제 크기로. 각 계열의 L을 데스크톱 크기로 보여주고, 아래 한 줄이 그 스타일의 값입니다.
Specification
크기는 데스크톱 / 태블릿 / 모바일 순서. 이름은 계열과 크기만으로 부릅니다.
Rules
| 상황 | 규칙 |
|---|---|
| 숫자 | 금액·건수·날짜는 tabular-nums. 표에서 자릿수가 흔들리지 않게. |
| 금액 | 12,340,000원처럼 세 자리 쉼표, 단위는 붙여서. 축약(1.2천만)은 쓰지 않아요. |
| 날짜 | 2026.09.15, 기간은 2026.09.15 ~ 10.14, 남은 기간은 D-7. |
| 줄바꿈 | 한 줄로 끝나야 하는 셀은 truncate, 문장은 break-keep으로 단어를 자르지 않게. |
| 모바일 입력 | iOS Safari는 16px 미만 입력에 포커스하면 화면을 확대해요. 640px 아래에서는 입력 글자를 16px로 강제합니다. |
Layout
화면 규격과 구간, 여백 단위, 컬럼 그리드. 리바운드의 모든 화면은 이 네 가지 위에 놓입니다.
Artboard size
해상도별로 모든 화면을 그리지 않고 아래 대표 규격만 설계합니다. 그 사이 크기는 그리드가 알아서 대응해요.
| 환경 | 너비 | 높이 | 최대 너비 |
|---|---|---|---|
| Web desktop | 1440px | 960px | 1280px |
| Web tablet | 768px | 1024px | — |
| Web mobile | 390px | 844px | — |
Breakpoint
네 구간. 데스크톱부터는 본문 폭을 1280px에서 멈추고 가운데에 놓습니다.
| 명칭 | 대응 환경 | 너비 | 최대 너비 |
|---|---|---|---|
| Mobile | 모바일 | 360 ~ 639px | — |
| Tablet | 태블릿 | 640 ~ 1023px | — |
| Desktop | 데스크톱 | 1024 ~ 1439px | 1280px (패딩 포함) |
| Wide | 데스크톱 대형 | 1440px ~ | 1280px (패딩 포함) |
Spacing
1 unit = 4px. 여백은 4의 배수로 잡고, 시각 보정이 필요할 때만 2px 단위로 움직입니다.
Grid
화면 너비에 맞게 늘어나는 컬럼 그리드. 컬럼은 비율이고 거터와 마진만 고정값입니다. 컬럼은 자유롭게 묶어서 쓸 수 있어요.
Mobile
4단 컬럼, 거터 16px, 마진 16px.
Tablet
8단 컬럼, 거터 24px, 마진 24px.
Desktop
12단 컬럼, 거터 24px, 마진 24px. 고객 페이지에서는 사이드바 256px 오른쪽 본문이 이 그리드 위에 놓입니다.
Radius
크기에 비례합니다. 작은 것은 6, 조작 요소는 8, 카드와 모달은 12, 동그라미는 999.
Elevation
그림자로 표면 사이의 거리를 표현합니다. 리바운드는 그림자를 거의 보이지 않을 만큼 옅게 쓰고, 떠 있는 정도만 네 단계로 나눕니다.
Level
바닥에 붙은 것부터 화면 위에 떠 있는 모달까지. 단계가 올라갈수록 그림자가 아래로 길어지고 조금 더 번집니다.
Layer
컴포넌트가 놓이는 층. 위 레벨은 아래 레벨을 항상 덮고, 같은 레벨끼리는 겹치지 않게 배치합니다.
| 레벨 | 그림자 | z-index | 컴포넌트 |
|---|---|---|---|
| Level 0 | None | 0 | 표, 리스트, 입력칸, 탭, 배지. 바닥에 붙어 있는 것 |
| Level 1 | Card | 10 | 카드, KPI 카드, 안내 배너, 사이드바 |
| Level 2 | Medium | 20 | 드롭다운, 팝오버, 툴팁, 날짜 선택. 열려 있는 동안만 떠 있는 것 |
| Level 3 | Modal | 40 · 토스트 50 | 모달, 다이얼로그, 토스트. 화면 전체 위에 놓이는 것 |
Style
| 명칭 | 토큰 | 값 |
|---|---|---|
| Card | shadow-card | 0 -2px 8px -2px rgba(16,24,40,.02) 0 6px 20px -6px rgba(16,24,40,.04) 0 2px 8px -2px rgba(16,24,40,.02) |
| Medium | shadow-md | 0 4px 8px -2px rgba(16,24,40,.08) 0 2px 4px -2px rgba(16,24,40,.06) |
| Modal | shadow-xl | 0 20px 25px -5px rgba(16,24,40,.1) 0 8px 10px -6px rgba(16,24,40,.1) |
Focus
키보드로 이동할 때만 3px 오렌지 링을 씁니다. 입력칸은 포커스에서 그림자 대신 테두리 색만 Information 파랑으로 바뀌어요.
Iconography
아이콘은 lucide 한 벌만 씁니다. 선 굵기 2, 끝은 둥글게, 기본 크기 16. 아래는 고객 페이지에서 실제로 쓰고 있는 아이콘이에요.
Search icons
이름으로 찾고, 아이콘을 누르면 컴포넌트 코드가 복사됩니다.
맞는 아이콘이 없어요.
Size
네 크기만 씁니다. 표 안과 12~13px 글자 옆은 14, 버튼·내비·리스트는 16, 모달 닫기와 섹션 헤더는 18, 빈 화면과 강조는 20.
Color
기본은 Label Assistive, 마우스를 올리면 Label Title. 내비에서는 회색이었다가 활성 시 Primary. 아이콘만 있는 버튼은 28×28 둥근 박스 안에 가운데로.
Components
화면을 만드는 조각들이에요. 스물여덟 개가 같은 문법을 씁니다. 회색 바탕에 흰 면, 오렌지는 행동과 진행에만, 파랑은 입력과 선택에만. 각 페이지는 미리보기 · Anatomy · Variants · States · Behavior · Usage · Specification · 코드 순서로 읽어요.
Actions
Data Display
채권 정보
| 채무자 | 원금 |
|---|---|
| 김리바 | 8,400,000 |
| 이바운 | 3,200,000 |
Inputs
Feedback
삭제할까요?
계좌 등록
계약이 끝났어요
Loading
Navigation
Button
행동을 실행하는 컴포넌트. 기본은 회색 Neutral이고, 오렌지 Primary는 화면에서 가장 중요한 한 곳에만 포인트로 씁니다. 배경 없는 Ghost, 위험한 일에만 Danger.
Anatomy
컨테이너, 앞 아이콘(선택), 라벨. 아이콘은 라벨 앞에만 오고 간격은 8.
- 1컨테이너 · 높이 36 · 좌우 16 · radius 8 · Fill/Normal
- 2앞 아이콘 · 16 · 라벨 색과 같음 · 라벨과 8
- 3라벨 · Label M 13 · 600 (Primary 700) · Label/Title
Variants
넷이면 충분합니다. 고민되면 Neutral, 화면의 방향을 정하는 한 곳만 Primary.
Sizes
S는 표 안과 카드 머리, M이 기본, L은 온보딩·빈 화면의 단 하나의 CTA. 폭은 자유지만 높이는 고정.
Layout
글자만, 앞 아이콘 + 글자, 아이콘만. 아이콘은 뜻을 보태는 경우에만 쓰고 L 크기의 CTA에는 넣지 않습니다.
States
색을 새로 정의하지 않습니다. 호버는 투명도, 눌림은 크기, 비활성은 투명도로만 표현해요.
Hierarchy
Primary 하나가 화면의 방향을 정하고, 나머지는 Neutral과 Ghost로 물러납니다.
Placement
데스크톱은 가로로 오른쪽 정렬, 간격 spacing-8. 모바일은 세로로 쌓고 폭을 채우며 주 행동이 위.
Label
무슨 일이 일어나는지 동사로. 두 어절 안에서 끝내고 느낌표와 영문은 쓰지 않습니다.
이렇게
- 위임 신청
- 계좌 등록
- 엑셀 내려받기
- 동의하고 계속
이건 피해요
- 확인(무엇을 확인하는지 모름)
- 제출하기 / ~하기 남발
- OK, Submit 같은 영문
- 느낌표 붙이기
Specification
| Variant | 배경 | 글자 | 호버 | 비활성 |
|---|---|---|---|---|
| Neutral | Fill/Normal #F0F0F0 | Label/Title | Fill/Strong #E4E4E4 | opacity .4 |
| Primary | Primary/Normal #FF5900 | Static/White | opacity .9 | opacity .4 |
| Ghost | 없음 | Label/Body | Fill/Normal 배경 · Label/Title | opacity .4 |
| Danger | System/Danger #EB003B | Static/White | opacity .9 | opacity .4 |
| Size | 높이 | 좌우 여백 | 글자 | Radius | 아이콘 |
|---|---|---|---|---|---|
| S | 32 | spacing-12 | Label S · Bold | 8 | 14 |
| M | 36 | spacing-16 | Label M · Bold | 8 | 16 |
| L | 48 | spacing-24 | Label L · Bold | 12 | 없음 |
| Icon only | 28 | — | — | 8 | 16 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| variant | neutral · primary · ghost · danger | neutral | 종류. 기본은 회색, 화면의 주 행동 하나만 primary |
| size | sm · md · lg | md | 크기. lg는 CTA 전용, 아이콘 불가 |
| icon | ReactNode | — | 앞 아이콘. lucide 16 |
| loading | boolean | false | 스피너 표시 + 비활성. 라벨은 호출하는 쪽에서 진행형으로 |
| disabled | boolean | false | opacity .4, 클릭 불가 |
| full | boolean | false | 폭 채움. 모바일 세로 배치에서 |
| type | button · submit | button | 폼 안에서는 명시. 기본값 submit이면 폼이 날아가요 |
쓰기
클래스
Tailwind로 쓸 때의 원형. src/index.css의 @layer components.
주의
| 항목 | 설명 |
|---|---|
| btn-outline | 흰 배경 + 1px 테두리 버튼은 줌 배율에서 선이 끊겨 보여서 Neutral(회색 채움)로 바꿔 가고 있어요. 새 화면에서는 쓰지 않습니다. |
| 검정 버튼 | bg-text-primary 버튼이 남아 있는 화면은 Primary로 교체 대상. |
| a 태그 | 이동은 <Link className="btn-neutral">로. 버튼처럼 보여도 링크는 링크로. |
Icon button
글자 없이 아이콘만 있는 버튼. 더보기, 닫기, 새로 고침처럼 뜻이 뻔한 행동에만 쓰고, 이름은 aria-label과 Tooltip으로 줍니다.
Anatomy
정사각 히트 영역 안에 아이콘 하나. 배경은 호버할 때만 보이고, 알림처럼 개수가 있으면 오른쪽 위에 배지.
- 1히트 영역 · 32 (S 28 · L 40) · radius 8 · 배경 없음 → 호버 Fill/Normal
- 2아이콘 · 18 (S 16 · L 20) · Label/Body · lucide 2px
- 3배지 · Count 16 · Primary · 오른쪽 위 -4 · 개수가 있을 때만
Variants
셋. 대부분은 배경 없는 Ghost. 눌러야 한다는 게 보여야 하면 Neutral, 화면의 유일한 행동이면 Primary.
Sizes
States
Behavior
| 동작 | 규칙 |
|---|---|
| 이름 | aria-label 필수. 마우스를 올리면 같은 이름이 Tooltip으로 |
| 아이콘 | 뜻이 한 가지로 읽히는 것만. 더보기 ⋯, 닫기 ×, 새로 고침, 내려받기, 편집, 삭제. 애매하면 글자 버튼 |
| 메뉴 | 더보기는 Menu를 열어요. 열린 동안 Pressed 상태 유지 |
| 위험 | 삭제 아이콘 버튼은 바로 지우지 않고 Alert로 한 번 물어요 |
| 간격 | 나란히 놓을 때 사이 4. 히트 영역이 붙어도 아이콘 사이는 16 이상 |
Usage
Specification
| 부분 | 크기 | 아이콘 | 색 | 여백 |
|---|---|---|---|---|
| Ghost | S 28 · M 32 · L 40 · radius 8 (L 10) | 16 · 18 · 20 | Label/Body · 호버 Fill/Normal · 눌림 Fill/Strong | 사이 4 |
| Neutral | 같음 | 같음 · Label/Title | Fill/Normal · 호버 Fill/Strong | — |
| Primary | 같음 | Static/White | Primary · 호버 90% | — |
| 배지 | 16 · radius 8 | Caption 10 700 | Primary · 99+ | 오른쪽 위 -4 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| icon | LucideIcon | — | 크기는 size가 정해요 |
| label | string | — | 필수. aria-label과 Tooltip에 같이 쓰여요 |
| variant | ghost · neutral · primary | ghost | — |
| size | sm · md · lg | md | 28 · 32 · 40 |
| count | number | — | 0이면 숨김, 99 넘으면 99+ |
| pressed | boolean | false | 메뉴가 열린 동안 true. aria-expanded로 나가요 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| p-1 rounded-lg 조각 | 모달 닫기, 헤더 아이콘들이 각자 p-1 hover:bg-surface로 그려져 있어요. IconButton으로. |
| Button 안 아이콘 | 글자 있는 버튼에 아이콘을 넣는 건 Button의 icon prop. 이 컴포넌트는 글자가 없을 때만. |
Badge
상태나 개수를 짧게 표시하는 컴포넌트. 배경을 채우지 않고 색 점 하나와 글자로만 말해서, 표 안에 수십 개가 늘어서도 시끄럽지 않아요. 누를 수 없습니다.
Anatomy
점과 라벨. 점이 뜻을 나르고 라벨이 이름을 붙입니다. 개수 배지는 컨테이너와 숫자만.
- 1점 · 6 원 · 톤 색 · 라벨과 6
- 2라벨 · Label S 12 600 · Label/Body
- 3개수 배지 · 높이 20 · radius 10 · Primary · Caption 11 700 tabular
Variants
넷. 표와 목록의 상태는 점(Status)이 기본이고, 카드나 제목 옆에서 눈에 띄어야 하면 옅게 채운 Tinted, 사진이나 어두운 면 위처럼 대비가 필요하면 Solid, 개수는 Count.
Tone
점 색은 System 컬러에서 옵니다. 뜻이 다르면 톤이 다르고, 톤이 같으면 뜻이 같아야 해요.
Placement
표에서는 상태 열에 하나, 카드에서는 제목 오른쪽 끝에 하나. 한 대상에 배지는 하나가 원칙, 많아도 둘.
Usage
Label
상태 이름을 그대로, 2~5자. 숫자와 글자를 한 배지에 섞지 않습니다.
이렇게
- 정상 상환
- 연체 주의
- 검토 중
- 종료
이건 피해요
- 연체 3회(숫자 섞기)
- 진행중입니다(문장)
- ACTIVE(영문)
- 정상!
Specification
| Variant | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| Status | 점 6 | Label S 12 600 · Label/Body | 점 = 톤 색 | 점과 6 |
| Tinted | 높이 22 (S 18) · radius 6 (S 5) | 12 600 (S 11) | 톤 10% 채움 + 톤 글자 · Neutral은 Fill/Normal + Label/Body | 좌우 8 (S 6) · 배지 사이 6 |
| Solid | 같음 | 12 600 | 톤 채움 + Static/White · Warning만 Label/Title | 같음 |
| Count | 높이 20 · 최소 폭 22 · radius 99 | Caption 11 700 tabular | Primary + Static/White | 좌우 6 |
| Variant | 글자 | 점 · 배경 | 간격 | 모양 |
|---|---|---|---|---|
| Status | Label S 12 · SemiBold · Label/Body | 점 6 · 톤 색 | 점과 글자 6 | 배경 없음 · 줄바꿈 없음 |
| Status · Neutral | Label/Assistive | 점 Label/Disable | 6 | 배경 없음 |
| Count | 11 · Bold · Static/White · tabular | Primary/Normal | 좌우 6 | 높이 20 · 폭 22+ · r999 |
| Tone | 점 색 | 토큰 |
|---|---|---|
| Success | #008A1E | System/Success |
| Warning | #FFB724 | System/Warning |
| Danger | #EB003B | System/Danger |
| Information | #2768FF | System/Information |
| Brand | #FF5900 | Primary/Normal |
| Neutral | #C6C6C6 | Label/Disable |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| tone | success · warning · danger · info · brand · neutral | neutral | 점 색. 뜻에 맞는 톤 하나 |
| children | string | — | 상태 이름. 2~5자 |
| Count · count | number | — | 개수. 99를 넘으면 99+로 표시 |
쓰기
클래스
지금 rebound-biz에 있는 이름과의 대응. 새 화면은 톤 이름으로 쓰고, 옛 이름은 교체 대상이에요.
주의
| 항목 | 설명 |
|---|---|
| Warning 색 | 옛 badge-warn은 오렌지 점이었어요. 오렌지는 행동 색이라 상태에 쓰지 않고, System/Warning 노랑으로 바꿉니다. |
| 누르는 배지 | 배지에 onClick을 달지 않아요. 필터로 쓰려면 Chip. |
Board row
공지, 문의, 알림처럼 글 목록의 한 줄. 제목과 한 줄 설명, 오른쪽에 날짜나 상태. 눌러서 상세로 가고, 읽으면 제목이 옅어집니다. 숫자 열이 많으면 Table.
Anatomy
왼쪽에 제목과 설명, 오른쪽에 메타와 chevron. 안 읽은 글은 제목 앞에 오렌지 점.
- 1행 · 높이 72 · 16 20 · 아래 Line/Alternative · 호버 Background/Alternative
- 2안 읽음 점 · 6 · Primary · 제목 앞 · 읽으면 사라짐
- 3제목 · Body M 15 600 · Label/Title · 한 줄 말줄임 · 읽으면 500 Label/Body
- 4설명 · Body S 13 · Label/Alternative · 한 줄 말줄임 · 위 2
- 5메타 · Caption 12 · Label/Alternative · 날짜 또는 Badge
- 6chevron · 16 · Line/Strong · 행 전체가 링크
Variants
넷. 공지는 Default, 문의처럼 상태가 있으면 With badge, 알림처럼 종류가 다르면 With icon, 제목만 있으면 Compact.
States
Behavior
| 동작 | 규칙 |
|---|---|
| 이동 | 행 전체가 링크. 누르면 상세로, 돌아오면 그 행이 읽음으로. 본문이 몇 줄이면 행 아래로 펼쳐도 돼요(미리보기처럼) |
| 읽음 | 상세를 열면 읽음. 목록에서 점만 지우고 순서는 바꾸지 않아요 |
| 개수 | 한 카드에 5~10행. 넘으면 아래에 "더 보기" Ghost 버튼, 무한 스크롤은 쓰지 않아요 |
| 빈 상태 | 행이 없으면 카드 안에 한 줄 "아직 알림이 없어요". Empty state |
| 날짜 | 오늘은 "10분 전", 올해는 "9.17", 지난해는 "2025.12.3" |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 행 | 높이 72 · Compact 52 | — | Background/Normal · 아래 Line/Alternative · 호버 Background/Alternative | 16 20 · 요소 사이 14 |
| 제목 | 한 줄 말줄임 | Body M 15 600 · 읽음 500 | Label/Title · 읽음 Label/Body | — |
| 설명 | 한 줄 말줄임 | Body S 13 | Label/Alternative | 위 2 |
| 안 읽음 점 | 6 | — | Primary | 제목과 6 |
| 아이콘 원 | 36 · radius 10 · 아이콘 16 | — | Fill/Normal · Label/Body | 글과 14 |
| 메타 · chevron | chevron 16 | Caption 12 | Label/Alternative · chevron Line/Strong | 사이 8 |
| 카드 | radius 12 | — | Card Default | 안쪽 0 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| title · description | string | — | description 없으면 Compact |
| meta | string · ReactNode | — | 날짜 문자열 또는 Badge |
| icon | LucideIcon | — | 왼쪽 원 |
| unread | boolean | false | 점 + 제목 600 |
| to · onClick | string · fn | — | 없으면 chevron도 없고 누를 수 없어요 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| NoticeCard | 공지를 카드 하나씩 그리던 NoticeCard는 BoardRow 목록으로. 카드 안에 행으로 쌓아요. |
| Table과 구분 | 비교할 숫자 열이 둘 이상이면 Table. 글이 주인공이면 BoardRow. |
| a vs button | to가 있으면 a(NavLink), onClick만 있으면 button. div에 onClick 금지. |
Form
입력칸은 흰 바탕에 얇은 테두리. 포커스하면 테두리만 Information 파랑으로 바뀌고 그림자는 생기지 않아요. 라벨은 위에, 도움말은 아래에.
등록된 채권 정보와 같아야 해요
10자리 숫자만 입력해 주세요
Anatomy
라벨, 필드, 도움말. 셋이 한 묶음이고 위에서 아래로 읽힙니다. 도움말 자리에 오류가 대신 들어가요.
등록된 채권 정보와 같아야 해요
2- 1라벨 · Label S 13 600 · Label/Title · 아래 6. 선택 항목은 뒤에 (선택)
- 2필드 · 높이 40 · Body S 14 · Line/Normal 1px · radius 8. 플레이스홀더는 예시 값
- 3도움말 · Caption 12 · Label/Alternative · 위 6. 오류일 땐 Danger 글자와 테두리
Variants
넷. 글을 받으면 Text, 여러 줄이면 Textarea, 정해진 것 중 하나면 Select, 켜고 끄거나 고르면 Checkbox와 Radio.
Select
브라우저 기본 목록은 쓰지 않고 우리 메뉴를 그립니다. 닫혀 있을 땐 Text 필드와 같고, 열리면 아래로 6 떨어진 메뉴. 고른 항목은 오른쪽에 체크.
Sizes
둘. 기본은 40이고, 로그인과 온보딩처럼 필드가 화면의 주인공일 때만 48.
States
여섯. 포커스는 테두리 색만 Information으로 바뀌고, 오류는 테두리와 문구가 함께 Danger로.
10자리 숫자만 입력해 주세요
Layout
한 열. 필드 사이 20, 라벨은 항상 위. 시작일과 종료일처럼 짝인 짧은 값만 나란히 둡니다. 버튼은 맨 아래 오른쪽.
Validation
오류는 무엇을 어떻게 고칠지 말합니다. "유효하지 않은 값입니다" 대신 "10자리 숫자만 입력해 주세요".
| 상황 | 시점 | 표시 |
|---|---|---|
| 형식 오류 | 필드를 떠날 때 (blur) | 테두리 Danger + 도움말 자리에 오류 문구. 입력 중에는 지우지 않아요 |
| 빈 필수 값 | 제출할 때 | 첫 오류 필드로 스크롤하고 포커스. 상단 요약 배너는 쓰지 않아요 |
| 서버 오류 | 응답 후 | 관련 필드가 있으면 그 필드에, 없으면 폼 위에 한 줄 |
| 도움말과 오류 | — | 같은 자리를 씁니다. 오류가 있으면 도움말은 사라져요 |
| 필수 · 선택 | — | 대부분이 필수라 표시하지 않고, 선택 항목만 라벨 뒤에 (선택) |
| 자동 형식 | 입력 중 | 전화번호와 사업자번호는 하이픈을 자동으로. 금액은 천 단위 콤마 |
Usage
등록된 채권 정보와 같아야 해요
하이픈 없이 입력해 주세요
10자리 숫자만 입력해 주세요
Specification
| 부분 | 크기 | 글 | 색 · 선 | 여백 |
|---|---|---|---|---|
| 라벨 | — | Label S 13 600 | Label/Title · (선택) Label/Alternative 500 | 아래 6 |
| Text · Select M | 높이 40 · radius 8 | Body S 14 | Background/Normal · Line/Normal 1px | 좌우 14 · Select 오른쪽 36 |
| Text L | 높이 48 · radius 10 | Body M 15 | 같음 | 좌우 16 |
| Select 메뉴 | 폭 = 필드 · radius 12 · 항목 40 | Body S 14 · 선택 600 + 체크 14 | Background/Normal · Elevation Dropdown · 호버 Fill/Normal | 위 6 · 안쪽 4 · 항목 좌우 12 |
| Textarea | 최소 96 · radius 8 | Body S 14 · 행간 1.6 | 같음 | 10 14 |
| Checkbox · Radio | 16 · radius 4 / 원 | Body S 14 라벨 | Line/Strong 1px → 켜지면 Information 채움 | 라벨과 8 |
| Focus | — | — | Information 1px · 그림자 없음 | — |
| Error | — | Caption 12 | Danger 테두리와 글자 | 위 6 |
| Disabled · Read-only | — | Label/Disable · Label/Body | Background/Alternative 채움 · 선 Line/Alternative · 없음 | — |
| 도움말 | — | Caption 12 | Label/Alternative | 위 6 |
| 필드 사이 | 20 | — | — | 짝 필드 12 · 붙는 컨트롤 8 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| label | string | — | 항상 있어야 해요. 숨기려면 hideLabel로 시각만 숨김 |
| optional | boolean | false | 라벨 뒤에 (선택) |
| help · error | string | — | 같은 자리. error가 있으면 help 대신 보여요 |
| size | md · lg | md | 40 · 48 |
| disabled · readOnly | boolean | false | 회색 채움. readOnly는 복사 가능 |
| options · placeholder | { value, label }[] · string | — | SelectField. 여섯 개 넘으면 메뉴 안 스크롤 |
| format | phone · biz · money | — | 입력 중 하이픈, 콤마 자동 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| 라벨 클래스 세 가지 | 지금 제품에 13/bold, 13/semibold, sm/medium 라벨이 섞여 있어요. .field-label 하나로. |
| 모바일 16px | iOS 확대 방지용 16px 강제는 유지. 그래서 모바일 필드는 L 사이즈처럼 보여요. |
| focus ring | Tailwind 기본 ring과 브라우저 outline은 끕니다. 테두리 색만 Information으로. 체크박스·라디오·스위치와 같은 파랑이라 '입력 계열'이 한 색으로 묶여요. |
| 네이티브 select | 브라우저와 OS마다 다르게 열려요. role="listbox" 메뉴로 직접 그리고, 640 미만에서는 Bottom sheet로 열어요. |
| accent-color | 네이티브 checkbox, radio는 accent-color를 Information #2768FF로. 오렌지가 기본으로 들어가지 않게. |
Search field
목록에서 찾을 때 쓰는 입력칸. 회색 채움에 검색 아이콘, 글자가 있으면 지우기 버튼. 입력하는 동안 결과가 따라오고, 결과가 없으면 표가 빈 상태로 말해줘요.
Anatomy
왼쪽 아이콘, 글, 오른쪽 지우기. 라벨은 없고 플레이스홀더가 무엇을 찾을 수 있는지 말해요.
- 1컨테이너 · 높이 40 · radius 8 · Fill/Normal · 테두리 없음 · 포커스하면 흰 배경 + Information 테두리
- 2검색 아이콘 · 16 · Label/Alternative
- 3글 · Body S 14 · Label/Title · 플레이스홀더는 무엇을 찾을 수 있는지
- 4지우기 · 원 18 Line/Strong + X 10 · 글자가 있을 때만
Variants
넷. 표 위 도구 줄에 두는 게 기본이고, 조건이 많으면 옆에 필터 버튼, 좁은 자리엔 Compact. 결과가 없으면 표가 말해요.
| 채무자 | 원금 | 상태 |
|---|---|---|
| '홍길동'으로 찾은 결과가 없어요. | ||
States
Behavior
| 동작 | 규칙 |
|---|---|
| 검색 | 입력을 멈추고 300ms 뒤 자동으로. Enter는 바로. 검색 버튼은 없어요 |
| 지우기 | X를 누르거나 ESC. 비우면 전체 목록으로 돌아가고 포커스는 남아요 |
| 결과 없음 | 표 자리에 "'김리'로 찾은 결과가 없어요" + 지우기 버튼. 검색어를 문장에 넣어요 |
| 범위 | 플레이스홀더에 적은 항목만. "채무자 이름, 사업자번호"면 그 둘로만 찾아요 |
| 유지 | 검색어는 URL 쿼리(?q=)에. 새로 고쳐도, 돌아와도 남아요 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 컨테이너 | 높이 40 (S 32) · radius 8 · 폭 240~320 | Body S 14 (S 13) | Fill/Normal · 포커스 Background/Normal + Information 1px | 좌우 12 · 안쪽 간격 8 |
| 아이콘 | 16 (S 14) | — | Label/Alternative | — |
| 지우기 | 원 18 · X 10 | — | Line/Strong · 호버 Label/Alternative | — |
| 시간 | — | — | — | debounce 300ms |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| value · onChange | string · fn | — | onChange는 300ms debounce 뒤. onSubmit은 Enter |
| placeholder | string | '검색' | 무엇으로 찾는지 |
| size | md · sm | md | 40 · 32 |
| syncQuery | string | — | 'q'처럼 주면 URL 쿼리와 동기화 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| type="search" | 브라우저 기본 지우기(X)가 따로 생겨요. appearance none으로 끄고 우리 지우기만. |
| role | input에 role="searchbox", 감싸는 form에 role="search". 결과 수는 aria-live로. |
Radio
여럿 중 하나만 고르는 동그란 칸. 둘에서 다섯 개를 한눈에 보여줄 때 쓰고, 그보다 많으면 Select. 켜고 끄는 거면 Checkbox나 Switch. 고른 색은 Information 파랑.
Anatomy
16 동그라미와 안의 점, 오른쪽에 라벨. 설명이 있으면 라벨 아래. 라벨을 눌러도 골라져요.
- 1원 · 16 · Line/Strong 1 → 고르면 Information 링 5
- 2점 · 6 · Static/White · 링 안쪽
- 3라벨 · Body S 14 · Label/Title
- 4설명 · Caption 12.5 · Label/Alternative · 위 2
Variants
넷. 세로 목록이 기본, 짧은 값 셋 이하면 가로, 설명이 붙으면 With description, 큼직하게 보여야 하면 Card.
매월
매월
Sizes
States
하나를 골라 주세요
Behavior
| 동작 | 규칙 |
|---|---|
| 고르기 | 하나를 고르면 다른 건 풀려요. 고른 걸 다시 눌러도 풀리지 않아요 |
| 기본값 | 대부분 하나가 미리 골라져 있어요. 꼭 사용자가 정해야 하면 비워 두고 제출 때 Error |
| 개수 | 2~5개. 여섯이 넘으면 Select, 둘인데 켜고 끄는 뜻이면 Switch나 Checkbox |
| 키보드 | 그룹에 Tab으로 들어가고 ↑↓로 옮겨요. 옮기는 순간 골라져요 |
| 라벨 | 원, 라벨, 설명 어디를 눌러도. 그룹 위엔 무엇을 고르는지 라벨 하나 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 원 M | 16 · 선 1 · 고르면 링 5 | — | Line/Strong → Information · Error Danger | 라벨과 8 |
| 원 L | 20 · 링 6 | 라벨 15 | 같음 | 라벨과 10 |
| 라벨 · 설명 | — | Body S 14 · Caption 12.5 | Label/Title · Label/Alternative | 설명 위 2 |
| 그룹 | — | 그룹 라벨 Label S 13 600 | — | 세로 12 · 가로 24 · 라벨 아래 8 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| value · onChange | T · fn | — | RadioGroup에 |
| options | { value, label, description?, disabled? }[] | — | 2~5개 |
| label | string | — | 그룹 라벨. 없으면 aria-label |
| direction | vertical · horizontal | vertical | horizontal은 셋 이하 |
| size | md · lg | md | 16 · 20 |
| error | string | — | 아무것도 안 골랐을 때 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| role | 그룹은 role="radiogroup" + aria-labelledby. 항목은 진짜 input type=radio를 sr-only로 두고 점을 그려요. |
| 플랜 선택 | PlanConfirm의 플랜 고르기는 Card Selectable(Radio 의미)로. 버튼 여러 개로 만들지 않아요. |
Switch
켜고 끄는 스위치. 누르는 순간 바로 적용되는 설정에만 씁니다. 저장 버튼을 눌러야 반영되면 Checkbox. 켜진 색은 Checkbox와 같은 Information 파랑.
Anatomy
트랙과 손잡이. 켜지면 트랙이 파랗게 되고 손잡이가 오른쪽으로. 라벨은 왼쪽, 설명은 그 아래.
- 1트랙 · 44×24 · radius 12 · 꺼짐 Line/Strong · 켜짐 Information
- 2손잡이 · 20 · Static/White · 그림자 살짝 · 왼쪽 ↔ 오른쪽 200ms
- 3라벨 · Body S 14 600 · Label/Title · 누르면 스위치도 바뀜
- 4설명 · Caption 12.5 · Label/Alternative · 있어도 없어도
Variants
셋. 설정 화면의 행은 List row, 폼 안에 한 줄로 두면 Inline, 스위치만 놓으면 Bare.
States
Behavior
| 동작 | 규칙 |
|---|---|
| 적용 | 누르는 순간 저장. 서버 응답을 기다리는 동안 손잡이는 이미 넘어가 있고, 실패하면 되돌리며 Toast |
| 라벨 | 라벨과 설명을 눌러도 바뀜. 라벨은 켜졌을 때의 상태를 말해요("상환 알림 문자", "문자 보내기 켜기" 아님) |
| 확인 | 끄면 되돌리기 어려운 것(자동이체 해지)은 Alert로 한 번 물어요 |
| 키보드 | Space로 토글. role="switch", aria-checked |
| Checkbox와 | 저장 버튼이 있는 폼 안에서는 Switch를 쓰지 않아요. 여러 개를 고르는 것도 Checkbox |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 트랙 M | 44×24 · radius 12 | — | 꺼짐 Line/Strong #C6C6C6 · 켜짐 Information #2768FF | 라벨과 16 |
| 트랙 S | 36×20 · radius 10 | — | 같음 | 라벨과 12 |
| 손잡이 | 20 (S 16) · 안쪽 2 | — | Static/White · 그림자 0 1 2 15% | 이동 200ms |
| 라벨 · 설명 | — | Body S 14 600 · Caption 12.5 | Label/Title · Label/Alternative | 행 위아래 14 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| checked · onChange | boolean · fn | — | onChange 안에서 바로 저장. 실패 시 되돌리기 |
| label · description | string | — | 없으면 aria-label 필수 |
| size | md · sm | md | 44×24 · 36×20 |
| disabled | boolean | false | 이유는 Tooltip으로 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| role | button role="switch" aria-checked. input type=checkbox로 만들면 스크린리더가 체크박스라고 읽어요. |
| Settings 화면 | 지금 Settings의 알림 설정은 Checkbox + 저장 버튼이에요. 바로 저장되는 항목은 Switch row로 바꿔요. |
Textarea
여러 줄 글을 받는 입력칸. 예상되는 글 양에 맞춰 시작 높이를 정해 두고, 넘치면 최대 줄까지 자동으로 늘어난 뒤 스크롤. 손잡이로 늘리는 건 없어요. 글자 수 제한이 있으면 오른쪽 아래에 세어 줍니다.
Anatomy
라벨, 필드, 오른쪽 아래 글자 수. 도움말이 있으면 글자 수와 같은 줄 왼쪽에.
- 1라벨 · Label S 13 600 · Text 필드와 같음
- 2필드 · 시작 3줄(96) → 최대 8줄 자동 · 10 14 · Body S 14 · 행간 1.6 · radius 8 · 손잡이 없음
- 3도움말 · Caption 12 · Label/Alternative · 왼쪽
- 4글자 수 · Caption 12 tabular · 오른쪽 · 넘으면 Danger
Variants
글 양으로 셋을 고릅니다. 한두 문장이면 Short, 보통 메모는 Default, 사유나 긴 설명은 Long. 모두 글에 맞춰 최대 줄까지 자동으로 늘어나요. 제한이 있으면 Counter를 붙여요.
States
Behavior
| 동작 | 규칙 |
|---|---|
| Enter | 줄바꿈. 제출은 버튼으로만. ⌘/Ctrl+Enter로 제출은 허용 |
| 크기 | 시작 높이는 예상 글 양으로 정해 두고, 글이 넘치면 한 줄씩 늘어나요. 최대 줄을 넘으면 안에서 스크롤. 손잡이로 늘리게 두지 않아요 |
| 글자 수 | 입력하는 동안 실시간. 제한을 넘어도 입력은 막지 않고 Danger로 알려요. 제출 때 막아요 |
| 붙여넣기 | 서식은 버리고 글만. 줄바꿈은 유지 |
| 모바일 | 16px 강제(확대 방지). 키보드가 올라오면 필드가 보이도록 스크롤 |
Usage
Specification
| 부분 | 크기 | 글 | 색 · 선 | 여백 |
|---|---|---|---|---|
| 필드 | Short 64→4줄 · Default 96→8줄 · Long 144→12줄 · radius 8 | Body S 14 · 행간 1.6 (한 줄 22.4) | Background/Normal · Line/Normal 1px · 손잡이 없음 | 10 14 |
| 글자 수 | — | Caption 12 tabular | Label/Alternative · 초과 Danger | 위 6 · 오른쪽 |
| Focus · Error · Disabled | — | — | Text 필드와 같음 | — |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| rows · maxRows | number | 3 · 8 | 시작 줄과 최대 줄. Short 2·4, Long 6·12 |
| maxLength | number | — | 주면 글자 수가 보여요. 입력은 막지 않아요 |
| label · help · error | string | — | TextField와 같음 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| maxlength 속성 | HTML maxlength는 입력을 뚝 끊어요. 쓰지 말고 Counter로 알려요. |
| resize | resize: none. 사용자가 손잡이로 늘리지 않고 글에 맞춰 자동으로. 높이는 rows·maxRows로 정해요. |
Time picker
시각을 고르는 필드. 닫혀 있을 땐 시계 아이콘이 붙은 Select, 열리면 시와 분 두 열. 직접 타이핑해도 되고, 분은 5 단위.
Anatomy
트리거는 Select와 같고 앞에 시계 아이콘. 메뉴는 시 열과 분 열, 고른 값은 가운데에 진하게.
- 1트리거 · Text 필드와 같음 · 포커스 Information 테두리 · 값은 HH:MM tabular
- 2시계 아이콘 · 16 · Label/Alternative
- 3시 열 · 00~23 · 행 36 · 고른 값이 가운데 오게 스크롤
- 4고른 값 · Fill/Normal 채움 · Label/Title 600
- 5메뉴 · 폭 = 필드 · 높이 180 · radius 12 · Elevation Dropdown · 분 열은 5 단위
Variants
넷. 시각 하나면 Time, 시작과 끝이면 Range, 날짜와 함께면 Date + time. 모바일에서는 같은 두 열이 Bottom sheet로.
발송 시각
States
00:00~23:59 사이로
Behavior
| 동작 | 규칙 |
|---|---|
| 열기 | 클릭하거나 포커스. 고른 값이 두 열 가운데에 오도록 스크롤해 둬요 |
| 고르기 | 시를 고르면 분 열로 포커스, 분을 고르면 닫혀요. 둘 다 골라야 값이 바뀜 |
| 직접 입력 | 숫자만 치면 콜론이 자동으로. 0930 → 09:30. 범위 밖이면 Error, 필드를 떠날 때 가장 가까운 5분으로 |
| 키보드 | ↑↓로 열 안 이동, ←→로 열 바꾸기, Enter 확정, ESC 닫기 |
| Range | 시작을 고르면 끝 필드가 열리고, 끝은 시작 이후만 고를 수 있어요 |
| 모바일 | 640 미만에서 Bottom sheet에 같은 두 열. OS 기본 피커는 쓰지 않아요 |
Usage
평일 09:00~18:00에만 보내요
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 트리거 | 높이 40 · radius 8 | Body S 14 tabular | Text 필드와 같음 · 아이콘 Label/Alternative | 좌우 14 · 아이콘과 8 |
| 메뉴 | 폭 = 필드 · 높이 180 · radius 12 | — | Background/Normal · Elevation Dropdown | 위 6 · 안쪽 4 · 열 사이 4 |
| 행 | 36 · radius 8 | Body S 14 tabular · 고른 값 600 | Label/Body · 고른 값 Fill/Normal + Label/Title · 호버 Fill/Normal | — |
| Range | 필드 둘 + ~ | ~ Label/Alternative | — | 사이 8 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| value · onChange | 'HH:MM' · fn | — | 24시간 문자열 |
| step | 1 · 5 · 10 · 15 · 30 | 5 | 분 단위 |
| min · max | 'HH:MM' | — | 고를 수 있는 범위. 밖은 흐리게 |
| range | boolean | false | true면 [start, end] 값 |
| label · help · error | string | — | TextField와 같음 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| input type="time" | 브라우저마다 다르게 그려요. 트리거는 text로 두고 메뉴를 직접 그려요. |
| Select 둘 | 시·분을 Select 둘로 나눈 화면이 있어요. TimeField 하나로. |
| 시간대 | 값은 KST 기준 문자열만. Date 객체로 넘기지 않아요. |
Text field
한 줄 글을 받는 기본 입력칸. 라벨 위, 메시지 아래, 필드 안에는 앞 아이콘이나 단위, 지우기, 상태 아이콘이 들어갈 수 있어요. 형식이 있으면 입력하는 동안 맞춰 주고, 맞는지 틀린지는 필드를 떠날 때 말합니다.
Anatomy
라벨, 필드, 메시지. 필드 안은 왼쪽에 아이콘이나 앞 단위, 가운데 글, 오른쪽 자리엔 지우기 · 상태 아이콘 · 뒤 단위 중 하나만.
- 1라벨 · Label S 13 600 · 아래 6 · 선택 항목은 (선택)
- 2필드 · 높이 40 · Line/Normal 1px · radius 8 · 좌우 14 · 안쪽 요소 사이 8
- 3앞 아이콘 또는 앞 단위(₩) · 16 · Label/Alternative
- 4글 · Body S 14 · Label/Title · 플레이스홀더 Label/Alternative
- 5오른쪽 자리 · 하나만 · 포커스 중엔 지우기(원 18), 떠나면 상태 아이콘(채운 원 16 · 확인 중 스피너 · 통과 Success · 오류 Danger), 단위가 있으면 뒤 단위
- 6메시지 · Caption 12 · 위 6 · 도움말 Label/Alternative → 통과 Success · 오류 Danger · 앞에 채운 원 14. 한 자리에 하나
Variants
여섯. 대부분 Default고, 값에 단위가 있으면 Affix, 뜻이 아이콘으로 빨리 읽히면 Leading icon, 자주 지우면 Clearable, 필드 옆 행동이 붙으면 Action, 비밀번호는 Password.
Sizes
States
일곱. 포커스는 테두리만 파랗게, 통과는 초록 체크와 메시지, 오류는 빨간 테두리와 메시지. 확인 중엔 스피너.
Field feedback
틀렸다고만 하지 말고 어떻게 고치면 되는지. 입력 중엔 빨갛게 하지 않고, 필드를 떠날 때 판정해요. 서버 확인은 입력을 멈춘 뒤 500ms. 직접 써 보세요.
| 상황 | 시점 | 표시 | 문구 |
|---|---|---|---|
| 형식 오류 | 떠날 때(blur) | Danger 테두리 + X + 메시지 | "영문 소문자, 숫자, 밑줄 4~20자" 처럼 고치는 법 |
| 서버 확인 | 멈춘 뒤 500ms | 스피너 S + "확인하는 중" → 결과 | "사용할 수 있어요" · "이미 쓰고 있는 아이디예요. 다른 아이디를 골라 주세요" |
| 규칙 여러 개 | 입력 중 실시간 | 체크리스트 · 채우면 Success | 규칙 하나에 한 줄, 셋까지. 못 채운 건 제출 때만 Danger |
| 두 값 비교 | 둘째 필드 떠날 때 | 체크 또는 Danger | "비밀번호가 서로 달라요" |
| 고친 뒤 | 다시 입력하는 순간 | 오류 표시 지움 | 떠날 때 다시 판정. 타이핑 중엔 조용히 |
Behavior
| 동작 | 규칙 |
|---|---|
| 형식 맞춤 | 전화번호 하이픈, 금액 콤마, 사업자번호 하이픈은 입력하는 동안 자동. 저장값은 숫자만 |
| 오른쪽 자리 | 한 번에 하나. 포커스 중 글자가 있으면 지우기, 떠나면 상태 아이콘. 지우기를 누르면 비우고 포커스 유지. 뒤 단위가 있는 필드엔 지우기를 두지 않아요 |
| 비밀번호 | 눈 아이콘으로 보기·숨기기. 붙여넣기와 자동 완성을 막지 않아요 |
| 단위 | ₩처럼 앞, 원·%처럼 뒤. 값은 왼쪽 정렬 그대로 |
| Enter | 폼 안이면 제출. 필드 하나만 있는 검색은 Search field |
| 모바일 | 16px 강제(확대 방지), inputmode로 숫자 키패드 |
Usage
Specification
| 부분 | 크기 | 글 | 색 · 선 | 여백 |
|---|---|---|---|---|
| 필드 M | 높이 40 · radius 8 | Body S 14 | Background/Normal · Line/Normal 1px | 좌우 14 · 안쪽 8 |
| 필드 L | 높이 48 · radius 10 | Body M 15 | 같음 | 좌우 16 |
| 앞 아이콘 · 단위 | 16 | 단위 14 | Label/Alternative | 글과 8 |
| 지우기 | 원 18 · X 10 | — | Line/Strong · 호버 Label/Alternative | — |
| 상태 아이콘 | 채운 원 16 (메시지 앞 14) · 스피너 S 16 | — | Success #008A1E · Danger #EB003B · 글리프 Static/White | — |
| 눈 | 아이콘 16 · 히트 28 | — | Label/Alternative → 호버 Label/Body | 오른쪽 -6 |
| 메시지 | — | Caption 12 | Label/Alternative · Success · Danger | 위 6 · 아이콘 14와 6 |
| 규칙 목록 | 체크 원 14 | Caption 12 | Line/Strong → Success 채움 | 위 8 · 줄 사이 4 |
| Focus · Error · Disabled · Read-only | — | — | Information 1px · Danger 1px · Background/Alternative + Label/Disable · Background/Alternative 선 없음 | — |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| label · help | string | — | 라벨 필수. help는 메시지 자리의 기본 글 |
| status · message | idle · checking · ok · error · string | idle | 상태 아이콘과 메시지 색이 함께. message가 help를 대신해요 |
| prefix · suffix | string | — | ₩ · 원 · % |
| leadingIcon | LucideIcon | — | 16 |
| clearable | boolean | false | 글자 있을 때 지우기 |
| type | text · password · email · tel | text | password면 눈 아이콘이 붙어요 |
| format | phone · biz · money | — | 입력 중 자동. onChange엔 숫자만 |
| rules | { label, test }[] | — | 체크리스트. 셋까지 |
| action | { label, onClick, disabled? } | — | 오른쪽 Neutral 버튼 |
| size | md · lg | md | 40 · 48 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| .input 클래스 | 지금 제품의 .input은 input 요소 하나예요. 아이콘·단위·상태를 넣으려면 감싸는 .field가 필요해서 TextField 컴포넌트로 옮겨요. |
| 회원가입 폼 | 아이디 중복은 제출 때가 아니라 입력 중 확인으로. 비밀번호 규칙은 문장이 아니라 체크리스트로. |
| aria | 메시지에 id를 주고 input의 aria-describedby로 연결. 오류일 때 aria-invalid. |
Checkbox
여러 개를 고르거나 하나를 켜고 끄는 네모 칸. 저장 버튼과 함께 쓰는 폼 안의 선택이에요. 바로 적용되면 Switch, 여럿 중 하나만 고르면 Radio. 켜진 색은 Information 파랑.
Anatomy
16 네모 칸과 체크, 오른쪽에 라벨. 설명이 있으면 라벨 아래. 라벨을 눌러도 바뀌어요.
- 1칸 · 16 · radius 4 · Line/Strong 1 → 켜지면 Information 채움
- 2체크 · 10 · Static/White · 선 3
- 3라벨 · Body S 14 · Label/Title · 뒤에 (필수)는 Danger, (선택)은 Label/Alternative
- 4설명 · Caption 12.5 · Label/Alternative · 위 2
Variants
넷. 하나면 Single, 설명이 붙으면 With description, 여러 항목은 Group, 표 머리글처럼 전체 선택은 Indeterminate.
| 채무자 | 원금 | |
|---|---|---|
| 김리바 | 8,400,000 | |
| 이바운 | 3,200,000 |
Sizes
States
동의해야 계속할 수 있어요
Behavior
| 동작 | 규칙 |
|---|---|
| 토글 | 칸, 라벨, 설명 어디를 눌러도. Space로도 |
| 전체 선택 | 모두 켜져 있으면 체크, 일부면 Indeterminate, 없으면 빈 칸. Indeterminate를 누르면 전체 선택 |
| 필수 | 라벨 뒤 (필수). 제출할 때 안 켜져 있으면 Error와 문구, 첫 오류로 스크롤 |
| 저장 | 폼의 저장 버튼으로 반영. 누르는 즉시 적용되어야 하면 Switch |
| Radio와 | 여럿 중 하나만 고르면 Radio. 체크박스 여러 개를 배타적으로 만들지 않아요 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 칸 M | 16 · radius 4 · 선 1 | — | Line/Strong → 켜짐 Information · Error Danger | 라벨과 8 |
| 칸 L | 20 · radius 5 | 라벨 15 | 같음 | 라벨과 10 |
| 체크 · 가로선 | 10 (L 14) · 선 3 | — | Static/White | — |
| 라벨 · 설명 | — | Body S 14 · Caption 12.5 | Label/Title · Label/Alternative | 설명 위 2 |
| (필수) · (선택) | — | 13 500 | Danger · Label/Alternative | 라벨과 4 |
| Group | — | — | — | 항목 사이 12 · 가로 배열 24 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| checked · onChange | boolean · fn | — | — |
| indeterminate | boolean | false | 일부 선택. checked보다 우선 |
| label · description | ReactNode · string | — | label 필수. 숨기면 aria-label |
| required · optional | boolean | false | (필수) · (선택) 표시 |
| size | md · lg | md | 16 · 20 |
| error | string | — | Danger 테두리 + 아래 문구 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| 네이티브 체크박스 | 지금 동의 화면은 input type=checkbox 기본 모양(accent 오렌지)이에요. sr-only로 숨기고 box를 그려요. |
| label for | 라벨과 input을 label 요소로 감싸요. div onClick으로 만들면 키보드로 못 켜요. |
| Indeterminate | HTML 속성이 아니라 JS 프로퍼티(el.indeterminate = true). ref로 넣어요. |
Date picker
날짜를 고르는 필드. 닫혀 있을 땐 달력 아이콘이 붙은 필드, 열리면 한 달 달력. 오늘은 점, 고른 날은 오렌지. 기간이면 시작과 끝을 순서대로 눌러요. 직접 타이핑해도 됩니다.
Anatomy
트리거는 Select와 같고 앞에 달력 아이콘. 달력은 월 이동 머리, 요일 줄, 날짜 격자, 아래에 빠른 선택.
- 1트리거 · Text 필드와 같음 · 달력 아이콘 16 · 값 YYYY.MM.DD tabular
- 2머리 · 연월 14 600 · 양쪽 이전·다음 달 아이콘 버튼 S
- 3요일 · Caption 11 · Label/Alternative · 일요일 시작
- 4오늘 · 아래 점 4 Primary · 다른 달 날짜는 Line/Strong
- 5고른 날 · 34 정사각 · Primary 채움 · radius 8 · Static/White 700
- 6빠른 선택 · Ghost S 버튼 · 위 Line/Alternative · 오늘, 이번 달 말처럼 자주 고르는 날
Variants
넷. 날짜 하나면 Single, 시작과 끝이면 Range, 달만 고르면 Month, 자주 고르는 날이 정해져 있으면 Presets.
States
날짜 칸의 상태. 오늘은 점으로만 표시하고, 고를 수 없는 날은 흐리게.
Behavior
| 동작 | 규칙 |
|---|---|
| 열기 | 클릭하거나 포커스. 값이 있으면 그 달, 없으면 이번 달을 보여요 |
| 고르기 | Single은 누르면 바로 닫혀요. Range는 시작 → 끝 두 번, 끝을 시작보다 앞에 누르면 새 시작으로 |
| 직접 입력 | 숫자만 치면 점이 자동으로. 20260925 → 2026.09.25. 없는 날이면 Error |
| 범위 | min·max 밖은 Disabled. 과거를 못 고르는 필드는 오늘 이전을 흐리게, 숨기지 않아요 |
| 키보드 | ←→ 하루, ↑↓ 한 주, PageUp·Down 한 달, Enter 확정, ESC 닫기 |
| 모바일 | 640 미만에서 Bottom sheet에 같은 달력. OS 기본 피커는 쓰지 않아요 |
Usage
오늘 이후만 고를 수 있어요
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 트리거 | 높이 40 · radius 8 | Body S 14 tabular | Text 필드와 같음 · 아이콘 Label/Alternative | 아이콘과 8 |
| 달력 | 폭 280 · radius 12 | — | Background/Normal · Elevation Dropdown | 위 6 · 안쪽 12 |
| 머리 | 아이콘 버튼 S 28 | 연월 14 600 | Label/Title | 아래 10 |
| 요일 | — | Caption 11 | Label/Alternative | 아래 4 |
| 날짜 칸 | 34 · radius 8 | 13 tabular · 고른 날 700 | Label/Title · 호버 Fill/Normal · 고른 날 Primary · 범위 Primary 10% · 다른 달·Disabled Line/Strong | 행 사이 2 |
| 오늘 | 점 4 | — | Primary | 아래 4 |
| 빠른 선택 | Ghost S | — | 위 Line/Alternative | 위 8 · 사이 6 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| value · onChange | 'YYYY.MM.DD' · fn | — | 문자열. Date 객체는 넘기지 않아요 |
| mode | date · range · month | date | range면 [start, end] |
| min · max | 'YYYY.MM.DD' | — | 밖은 Disabled |
| presets | { label, value }[] | — | 셋까지. 아래 Ghost 버튼 |
| label · help · error | string | — | TextField와 같음 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| input type="date" | 브라우저마다 다르고 형식을 못 정해요. 트리거는 text, 달력은 직접. |
| MonthCalendar | 상환 일정 화면의 큰 달력은 이 컴포넌트가 아니에요. 날짜 칸 스타일(오늘 점, 고른 날 Primary)만 맞춰요. |
| 시간대 | 값은 KST 날짜 문자열. toISOString()으로 하루 밀리는 실수 주의. |
Card
콘텐츠를 한 덩어리로 묶는 흰 면. 회색 페이지 위에 흰 카드를 놓아 색 대비만으로 구분하고, 테두리와 그림자는 쓰지 않습니다. 라운드는 12 하나.
계좌 인증
완료Anatomy
컨테이너 안에 머리, 몸통, 발. 머리는 제목과 배지나 작은 행동, 발은 버튼이 오른쪽 정렬. 몸통만 있어도 카드예요.
주식회사 리바운드
검토 중2- 1컨테이너 · Background/Normal · radius 12 · 안쪽 여백 spacing-24
- 2머리 · Title S 16 Bold + 배지 또는 Ghost 버튼 · 아래 16
- 3몸통 · Body M · Label/Body
- 4발 · 버튼 오른쪽 정렬 · 간격 8 · 위 20
Variants
넷. 대부분은 Default이고, 지표는 KPI, 고르는 것은 Selectable, 흰 배경 위에 놓일 때만 Elevated.
채권 정보
매월
매월
안내
Padding
안쪽 여백은 셋. 지표와 선택 카드는 20, 기본은 24, 온보딩과 로그인처럼 카드가 화면의 주인공이면 32.
States
Selectable만 상태가 있습니다. 나머지 카드는 누를 수 없어요.
매월
매월
매월
매월
Composition
카드 안에서 나눌 때는 가로선, 묶을 때는 회색 블록. 카드 안에 카드를 넣지 않습니다.
출금 계좌
신청 안내
Placement
회색 페이지 위에 카드 사이 간격 16. 지표는 3열, 그 아래 본문 카드는 폭을 채웁니다.
최근 상환
Usage
Specification
| Variant | 배경 | 테두리 · 그림자 | Radius | 안쪽 여백 |
|---|---|---|---|---|
| Default | Background/Normal | 없음 | 12 | 24 (S 20 · L 32) |
| KPI | Background/Normal | 없음 | 12 | 20 · 세로 간격 8 |
| Selectable | Fill/Normal → 선택 시 Primary 4% | 선택 시 Primary/Normal 1px | 12 | 20 |
| Elevated | Background/Normal | Elevation Card | 12 | 24 |
| 회색 블록 | Background/Alternative #F7F8FA | 없음 | 12 | 20 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| variant | default · kpi · selectable · elevated | default | 종류 |
| padding | sm · md · lg | md | 20 · 24 · 32 |
| title / action | ReactNode | — | 머리. action엔 배지나 Ghost 버튼 |
| footer | ReactNode | — | 발. 버튼은 오른쪽 정렬 |
| selected · onSelect | boolean · fn | — | selectable에서만 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| rounded-2xl | Tailwind 설정에서 2xl을 12px로 덮어썼어요. xl과 같은 값이라 어느 쪽을 써도 12. 새 코드는 xl로. |
| border border-border | 회색 페이지 위 카드에 테두리를 두른 화면이 남아 있어요. 교체 대상. |
| 선택 카드 링 | 선택 표시는 1px 테두리만. 글로우나 ring은 쓰지 않아요. |
Table
채권자 화면의 중심. 세로선 없이 가로선만, 머리글은 회색 띠, 마지막 행의 아래선은 지웁니다. 모든 열은 왼쪽 정렬이고 숫자는 tabular로 자릿수를 맞춥니다.
| 채무자 | 원금 | 상환률 | 상태 | 최근 입금 |
|---|---|---|---|---|
| 김리바 | 8,400,000 | 62% | 정상 상환 | 2026.09.10 |
| 이바운 | 3,200,000 | 18% | 연체 주의 | 2026.08.25 |
| 박그라 | 12,000,000 | 100% | 종료 | 2026.07.30 |
Anatomy
흰 컨테이너 안에 머리글 행과 본문 행, 그 사이의 가로선. 열 정렬은 아래 Alignment에서.
| 채무자 | 원금 | 상태 |
|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 |
| 이바운 | 3,200,000 | 연체 주의 |
- 1컨테이너 · Card Default · radius 12
- 2머리글 행 · 44 · Fill/Normal · Label S 600
- 3본문 행 · 48 · Body M · 숫자는 tabular 600
- 4가로선 · Line/Alternative · 마지막 행은 없음
Variants
넷. 기본 표에 필요한 것만 더합니다. 행을 누르면 이동하는 표는 오른쪽 끝에 화살표를, 여러 개 고르는 표는 왼쪽에 체크박스를, 합이 중요하면 맨 아래 합계 행을.
| 채무자 | 원금 | 상태 |
|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 |
| 이바운 | 3,200,000 | 연체 주의 |
| 채무자 | 원금 | 상태 | |
|---|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 | |
| 이바운 | 3,200,000 | 연체 주의 |
| 채무자 | 원금 | 상태 | |
|---|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 | |
| 이바운 | 3,200,000 | 연체 주의 |
| 채무자 | 원금 | 회수 |
|---|---|---|
| 김리바 | 8,400,000 | 5,200,000 |
| 이바운 | 3,200,000 | 580,000 |
| 합계 | 11,600,000 | 5,780,000 |
Head
머리글은 셋 중 하나. 제목만 있는 Text, 눌러서 정렬하는 Order, 조건을 고르는 Filter. 아이콘은 글자 오른쪽에 4 띄우고, 쓰는 중인 열만 진하게.
| 채무자 | 최근 입금 |
|---|
| 원금 | 상환률 |
|---|
| 상태 | 담당자 |
|---|
| 종류 | 표시 | 동작 |
|---|---|---|
| Text | 제목만 | 기본. 대부분의 열 |
| Order | chevrons-up-down 14 Line/Strong → 정렬 중 chevron-up · down Label/Title | 누를 때마다 오름 → 내림 → 해제. 한 번에 한 열만 정렬 |
| Filter | list-filter 14 Line/Strong → 적용 중 Primary | 누르면 조건 메뉴(Select 메뉴와 같은 모양). 적용 중이면 아이콘만 Primary |
Density
행 높이는 둘. 기본은 48이고, 한 화면에 많이 보여야 하는 관리 목록만 40.
| 채무자 | 원금 |
|---|---|
| 김리바 | 8,400,000 |
| 이바운 | 3,200,000 |
| 채무자 | 원금 |
|---|---|
| 김리바 | 8,400,000 |
| 이바운 | 3,200,000 |
States
행의 상태. 호버는 Row link와 Selectable에만 있고, 정보 표의 행은 아무 반응이 없어요.
| 김리바 | 840,000 |
| 김리바 | 840,000 |
| 김리바 | 840,000 |
| 김리바 | 840,000 |
Alignment
모든 열이 왼쪽. 열마다 정렬이 다르면 머리글과 본문이 어긋나 보여요. 숫자는 tabular 숫자로 자릿수를 세로로 맞추고, 단위는 머리글에 씁니다.
| 열 | 정렬 | 스타일 | 예 |
|---|---|---|---|
| 이름 · 글 | 왼쪽 | Body M · Label/Title 500 | 김리바 · 주식회사 리바운드 |
| 금액 · 비율 · 건수 | 왼쪽 | tabular · Label/Title 600 · 단위는 머리글에 | 8,400,000 · 62% |
| 날짜 | 왼쪽 | tabular · Label/Alternative · 14 | 2026.09.10 |
| 상태 | 왼쪽 | Badge Status | 정상 상환 · 연체 주의 |
| 행동 | 오른쪽 끝 | Ghost 버튼 하나 또는 chevron. 유일한 예외 | 상세 · › |
Empty · Pagination
결과가 없으면 표 자리에 한 문장과 되돌리는 버튼. 20건이 넘으면 아래에 페이지네이션, 무한 스크롤은 쓰지 않아요.
| 채무자 | 원금 | 상태 |
|---|---|---|
| 조건에 맞는 채무자가 없어요. | ||
Responsive
좁은 화면에서는 열을 숨기지 않고 표를 카드 목록으로 바꿉니다. 한 행이 한 카드, 이름과 금액이 첫 줄.
| 채무자 | 원금 | 상태 |
|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 |
| 이바운 | 3,200,000 | 연체 주의 |
| 박그라 | 12,000,000 | 종료 |
Usage
| 채무자 | 원금 | 상태 |
|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 |
| 이바운 | 3,200,000 | 연체 주의 |
| 채무자 | 원금 | 상태 |
|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 |
| 이바운 | 3,200,000 | 연체 주의 |
| 채무자 | 원금 | 상태 |
|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 |
| 이바운 | 3,200,000 | 연체 주의 |
| 채무자 | 원금 | 상태 |
|---|---|---|
| 김리바 | 8,400,000 | 정상 상환 |
| 이바운 | 3,200,000 | 연체 주의 |
| 박그라 | 12,000,000 | 종료 |
Specification
| 부분 | 높이 | 글 | 배경 · 선 | 여백 |
|---|---|---|---|---|
| 머리글 th | 44 (S 38) | Label S 13 600 · Label/Alternative | Fill/Normal · 아래 Line/Normal | 좌우 20 (S 16) |
| 본문 td | 48 (S 40) | Body M 15 · Label/Body | Background/Normal · 아래 Line/Alternative | 좌우 20 (S 16) |
| 숫자 열 | — | tabular · Label/Title 600 · 왼쪽 | — | — |
| Hover · Selected | — | — | Background/Alternative · Information 6% | — |
| 합계 행 | 48 | Bold · Label/Title | Background/Alternative · 위 Line/Normal | 좌우 20 |
| Empty | — | Body S 14 · Label/Alternative · 가운데 | — | 위아래 44 |
| Pagination | 32 | Label S 13 · 현재 Primary | Ghost · radius 8 | 간격 4 · 위아래 14 |
| 감싸는 면 | — | — | Card Default · radius 12 · overflow hidden | 0 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| columns | { key, title, width?, numeric?, render? }[] | — | 열 정의. numeric이면 tabular 숫자와 600 |
| columns[].sortable · filter | boolean · { options } | — | 머리글 Order · Filter. sort와 onSortChange, filters와 onFilterChange를 함께 |
| rows · rowKey | T[] · keyof T | — | 데이터와 키 |
| density | md · sm | md | 행 48 · 40 |
| onRowClick | (row) => void | — | 주면 Row link. 호버와 chevron이 붙어요 |
| selectable · selected · onSelect | boolean · Key[] · fn | — | 체크박스 열 |
| summary | Partial<T> | — | 합계 행 |
| empty | ReactNode | '데이터가 없어요.' | 결과 없을 때 본문 자리 |
| pagination | { page, limit, total, onChange } | — | 20건 초과 시. 표 아래에 붙어요 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| text-center | 지금 제품의 .th .td는 전부 가운데 정렬이에요. 새 코드는 전부 왼쪽. 기존 화면은 페이지 단위로 바꿔요. |
| border-y | .table-wrapper의 위아래 테두리는 빼고, 카드처럼 radius 12에 overflow hidden으로. 회색 페이지 위에서 흰 면으로 구분돼요. |
| Pagination 버튼 | 테두리 버튼에서 Ghost로. 현재 페이지만 Primary, 나머지는 배경 없음. |
| colSpan 빈 행 | 빈 상태는 <td colSpan>로 표 안에 넣어요. 표 밖에 따로 카드 만들지 않기. |
Modal
흐름을 끊어야 할 때만 띄웁니다. 입력이 있으면 Dialog, 문서를 읽어야 하면 Sheet, 모바일에선 Bottom sheet. 확인만 받으면 Alert, 성공 알림은 Toast.
Anatomy
어두운 스크림 위에 흰 컨테이너. 안은 머리, 몸통, 발이고 닫기는 머리 오른쪽 끝.
계좌 등록
상환금을 받을 계좌를 등록해 주세요
- 1스크림 · Static/Black 40% · 누르면 닫힘
- 2컨테이너 · Background/Normal · radius 12 · Elevation Modal
- 3머리 · Title M 18 800 + 설명 Body S · 닫기 X 18
- 4몸통 · 필드 사이 16
- 5발 · 버튼 오른쪽 · 취소 Neutral 다음 주 행동
Variants
셋. 무엇을 담는지에 따라 폭과 구조가 정해집니다. 모바일에서는 Dialog와 Sheet가 아래에서 올라오는 Bottom sheet가 돼요.
계좌 등록
상환금을 받을 계좌예요
정렬
Sizes
폭은 둘로 고정. 내용에 맞춰 늘리지 않고 둘 중 하나를 고릅니다. 확인만 받는 Alert는 360. 좌우 여백은 항상 16 이상.
Dialog
Sheet
Footer
버튼은 오른쪽, 둘까지. 취소가 왼쪽, 주 행동이 오른쪽. Sheet는 폭을 채우는 버튼 하나. 되돌릴 수 없는 결정은 Alert에서.
Behavior
| 동작 | 규칙 |
|---|---|
| 열기 | 가운데에서 96% → 100%로 150ms. 스크림은 같은 시간에 페이드. 첫 필드에 포커스 |
| 닫기 | ESC, 스크림 클릭, X, 취소. 넷 다 같은 결과. 입력 중이면 "작성 중인 내용이 사라져요" Alert 한 번 |
| 뒤 화면 | 스크롤 잠금. 포커스는 모달 안에서만 돌아요. 닫히면 열었던 버튼으로 돌아감 |
| 겹침 | 한 번에 하나. 모달 위에 뜰 수 있는 건 Alert만 |
| 긴 내용 | Sheet로. 머리와 발 고정, 몸통 스크롤, 최대 80vh. 그래도 길면 페이지로 |
| 모바일 | 640 미만에서 Bottom sheet. 좌우 여백 0, 위 모서리 16 |
Usage
계좌 등록
상환금을 받을 계좌예요
채무자 등록
저장되었습니다
계좌 등록
정말 닫을까요?
Specification
| 부분 | 크기 | 글 | 색 · 그림자 | 여백 |
|---|---|---|---|---|
| 스크림 | 화면 전체 | — | Static/Black 40% | 좌우 16 |
| 컨테이너 | 448 · 560 · radius 12 | — | Background/Normal · Elevation Modal | — |
| 머리 | — | Title M 18 800 · 설명 Body S 14 Label/Alternative | — | 24 24 8 · 설명 위 4 |
| 닫기 | 아이콘 18 · 히트 28 | — | Label/Alternative → 호버 Label/Title + Fill/Normal | 머리 오른쪽 끝 |
| 몸통 | — | Body S 14 | — | 16 24 0 · 항목 사이 16 |
| 발 | 버튼 M 36 | — | — | 20 24 24 · 버튼 사이 8 |
| Sheet 머리 · 발 | — | Title S 16 700 | 아래 · 위 Line/Normal | 16 24 · 발 버튼 full |
| Bottom sheet | 폭 100% · 위 radius 16 | — | 손잡이 36×4 Line/Normal | 손잡이 위 8 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| open · onClose | boolean · fn | — | ESC, 스크림, X가 모두 onClose를 불러요 |
| variant | dialog · sheet | dialog | 폭과 구조. 모바일에선 자동으로 bottom sheet. 확인만 받으면 AlertDialog |
| title · description | string | — | title은 필수. aria-labelledby로 연결 |
| footer | ReactNode | — | 버튼 둘까지. 취소가 먼저 |
| dirty | boolean | false | true면 닫을 때 한 번 더 물어요 |
| closeOnScrim | boolean | true | 결제처럼 중간에 끊으면 안 될 때만 false |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| 모달마다 다른 뼈대 | 지금은 모달 컴포넌트가 여덟 개 각자 div를 짜요. Modal 하나로 모으고 내용만 넘겨요. |
| 확인만 받을 때 | 필드 없이 묻기만 하면 Modal이 아니라 AlertDialog. 폭 360, 스크림 클릭으로 닫히지 않아요. |
| btn-outline | 취소 버튼의 테두리 스타일은 Neutral(회색 채움)로. |
| shadow-xl | Tailwind 기본 그림자 대신 Elevation의 shadow-modal 토큰. |
| ESC · 스크롤 잠금 | useEffect로 매번 쓰던 코드는 Modal 안으로. 페이지에서는 신경 쓰지 않아요. |
Alert
지금 결정을 받아야 할 때 띄우는 작은 대화상자. 제목은 질문, 버튼은 그 행동의 이름. 되돌릴 수 없는 일이면 Danger. 알리기만 할 거면 Toast.
Anatomy
스크림 위 폭 360의 흰 컨테이너. 제목과 설명, 그 아래 버튼 둘. 닫기 X는 없어요. 버튼으로만 답합니다.
채권을 삭제할까요?
삭제하면 상환 이력도 함께 지워져요.
- 1스크림 · Static/Black 40% · 눌러도 닫히지 않아요
- 2컨테이너 · 폭 360 · radius 12 · Elevation Modal · 안쪽 24
- 3제목 · Title S 16 700 · 질문형 · 한 줄
- 4설명 · Body S 14 · Label/Alternative · 두 줄까지 · 위 4
- 5취소 · Neutral · 항상 왼쪽 · 라벨은 "취소"
- 6주 행동 · Primary 또는 Danger · 행동의 이름 · 답이 하나면 Primary 글자 버튼
Variants
넷. 주 행동이 무엇인지에 따라 버튼 색이 정해지고, 답이 하나면 버튼도 하나. 라벨이 길거나 모바일이면 세로로 쌓아요.
변경 사항을 저장할까요?
저장하지 않으면 입력한 내용이 사라져요.
채권을 삭제할까요?
삭제하면 상환 이력도 함께 지워져요.
결제 수단이 만료됐어요
다음 자동이체 전에 카드를 다시 등록해 주세요.
위임 계약을 해지할까요?
진행 중인 회수도 함께 멈춰요.
Buttons
둘까지. 왼쪽이 취소, 오른쪽이 주 행동. 라벨은 "예/아니오"가 아니라 행동의 이름이고, 취소는 늘 "취소". 답이 하나뿐이면 채운 버튼 대신 Primary 글자 버튼으로 가볍게.
Behavior
| 동작 | 규칙 |
|---|---|
| 열기 | 가운데에서 96% → 100%로 150ms. 열리면 포커스는 Confirm에선 주 행동, Destructive에선 취소 |
| 닫기 | 버튼으로만. ESC는 취소와 같고, 스크림을 눌러도 닫히지 않아요. 실수로 결정하지 않게 |
| 뒤 화면 | 스크롤 잠금, 포커스 트랩. 닫히면 열었던 곳으로 돌아감 |
| 겹침 | Modal 위에 뜰 수 있는 유일한 것. Alert 위에 Alert는 없어요 |
| 처리 중 | 주 행동을 누르면 그 버튼만 loading, 취소는 비활성. 끝나면 닫히고 Toast |
| 모바일 | 가운데 그대로, 폭은 화면 − 32. Bottom sheet로 바꾸지 않아요. 라벨이 길면 Stacked |
Usage
계좌를 삭제할까요?
등록된 자동이체도 함께 해지돼요.
알림
정말 진행하시겠습니까?
저장되었습니다
계약을 해지할까요?
해지하면 진행 중인 회수 절차가 모두 중단되고, 채무자에게 발송된 안내도 취소되며, 이미 납부된 금액의 정산은 별도 문의가 필요하고…
Specification
| 부분 | 크기 | 글 | 색 · 그림자 | 여백 |
|---|---|---|---|---|
| 스크림 | 화면 전체 | — | Static/Black 40% | 좌우 16 |
| 컨테이너 | 폭 360 · radius 12 | — | Background/Normal · Elevation Modal | 24 24 24 |
| 제목 | — | Title S 16 700 · 행간 1.35 | Label/Title | — |
| 설명 | — | Body S 14 · 행간 1.5 · 두 줄까지 | Label/Alternative | 위 4 |
| 버튼 | M 36 · 최소 폭 64 | Label M 13 700 | 취소 Neutral · 주 행동 Primary 또는 Danger · 하나뿐이면 Primary 글자(Ghost) | 위 20 · 사이 8 · 오른쪽 정렬 |
| Stacked | 버튼 폭 100% | — | 주 행동이 위 | 사이 8 |
| 모바일 | 폭 화면 − 32 | — | — | 가운데 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| open · onClose | boolean · fn | — | onClose는 취소와 ESC에서만. 스크림 클릭은 무시 |
| title | string | — | 필수. 질문형 한 줄 |
| description | string | — | 두 줄까지 |
| confirm | { label, onClick, tone?: 'danger', loading? } | — | 주 행동. tone이 danger면 포커스가 취소로 가요 |
| cancel | { label } · false | { label: '취소' } | false면 Acknowledge. confirm이 Primary 글자 버튼으로 그려져요 |
| stacked | boolean | auto | 라벨 합이 길거나 640 미만이면 자동으로 세로 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| window.confirm | 브라우저 confirm()이 몇 곳 남아 있어요. 전부 AlertDialog로. |
| Modal과 구분 | 입력 필드가 하나라도 있으면 Modal Dialog. Alert에는 필드가 없어요. |
| role | role="alertdialog", aria-labelledby로 제목, aria-describedby로 설명. |
| 취소 라벨 | "닫기", "아니오", "나중에"를 쓰지 않아요. 늘 "취소". 취소가 어울리지 않으면 Acknowledge. |
Banner
화면 안에 남아서 지금 알아야 할 것을 말하는 띠. 정보, 성공, 주의, 위험 네 가지 톤이고 흐름을 막지 않아요. 답을 받아야 하면 Alert, 잠깐 알리면 Toast.
출금 계좌 잔액을 미리 확인해 주세요.
계약 검토가 끝나려면 사업자등록증과 통장 사본이 필요해요.
Anatomy
톤 색이 옅게 깔린 컨테이너에 아이콘, 제목, 설명. 필요하면 아래에 행동 버튼, 오른쪽 위에 닫기.
계약 검토가 끝나려면 통장 사본이 필요해요.
- 1컨테이너 · 톤 색 8% 채움 · radius 12 · 안쪽 여백 16 · 테두리 없음
- 2아이콘 · 20 · 톤 색 · 정보 info, 성공 circle-check, 주의 triangle-alert, 위험 circle-x
- 3제목 · Label M 14 600 · Label/Title · 한 줄
- 4설명 · Body S 13 · Label/Body · 위 2 · 두 줄까지
- 5행동 · Neutral S 버튼 · 하나만 · 위 10
- 6닫기 · X 18 · Label/Alternative · 정보와 성공에만
Variants
톤 넷. 톤은 상황이 정하고, 색은 배지의 System 색과 같습니다. 그냥 알려주면 정보, 잘 됐으면 성공, 곧 문제가 되면 주의, 지금 막혔으면 위험.
출금 계좌 잔액을 미리 확인해 주세요.
이제 상환금을 이 계좌로 받을 수 있어요.
계약 검토가 끝나려면 통장 사본이 필요해요.
잔액이 부족해요. 입금 후 다시 시도해 주세요.
Layout
내용 양에 따라 셋. 제목만 있으면 한 줄, 설명이 붙으면 두 줄, 할 일이 있으면 버튼까지. 폭은 놓인 곳을 가득 채워요.
출금 계좌 잔액을 미리 확인해 주세요.
계약 검토가 끝나려면 통장 사본이 필요해요.
Placement
페이지 제목 바로 아래, 또는 관련 있는 카드의 맨 위. 폼의 서버 오류는 폼 위에. 화면에 하나만 두고 스크롤을 따라오지 않아요.
출금 계좌
계좌번호를 다시 확인해 주세요.
Behavior
| 동작 | 규칙 |
|---|---|
| 닫기 | 정보와 성공만 닫을 수 있어요. 주의와 위험은 원인이 해결되면 저절로 사라져요 |
| 사라짐 | 시간이 지나도 사라지지 않아요. 몇 초 뒤 사라져야 하면 Toast |
| 여러 개 | 한 영역에 하나. 둘 이상이면 가장 급한 톤 하나만 보이고 나머지는 그 안에 목록으로 |
| 위치 | 놓인 자리에 고정. 스크롤을 따라오는 띠는 쓰지 않아요 |
| 확인 필요 | 사용자의 답이 필요하면 Banner가 아니라 Alert. 이 컴포넌트는 묻지 않아요 |
Usage
잔액이 부족해요. 입금 후 다시 시도해 주세요.
다시 시도해 주세요.
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 컨테이너 | 폭 100% · radius 12 | — | 톤 색 8% (Warning 14%) | 16 · 아이콘과 10 |
| 아이콘 | 20 | — | Information #2768FF · Success #008A1E · Warning #FFB724 · Danger #EB003B | — |
| 제목 | — | Label M 14 600 · 행간 20 | Label/Title | — |
| 설명 | — | Body S 13 · 행간 20 | Label/Body | 위 2 |
| 행동 | 버튼 S 32 | — | Neutral | 위 10 · 한 줄형은 오른쪽 끝 Ghost |
| 닫기 | 18 · 히트 28 | — | Label/Alternative | 오른콝 위 |
| 한 줄형 | 높이 52 | 제목만 | — | 세로 가운데 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| tone | info · success · warning · danger | info | 색과 아이콘이 함께 정해져요 |
| title | string | — | 필수. 한 줄 |
| description | string | — | 두 줄까지 |
| action | { label, onClick } | — | 하나만. Neutral S로 그려져요 |
| onClose | fn | — | 주면 닫기 버튼. info와 success에서만 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| bg-red-50 조각 | 지금 제품엔 text-status-bad와 bg-red-50을 조합한 오류 문구가 화면마다 달라요. Banner tone="danger" 하나로. |
| role | danger와 warning은 role="alert", info와 success는 role="status". 스크린리더가 바로 읽어요. |
| AlertDialog | 확인을 받는 대화상자는 이 컴포넌트가 아니에요. Alert 페이지. |
Tooltip
요소 위에 잠깐 뜨는 한 줄 설명. 어두운 회색 말풍선에 흰 글자. 마우스를 올리거나 포커스하면 나타나고, 없어도 쓸 수 있어야 해요. 꼭 알아야 하는 건 툴팁이 아니라 화면에 씁니다.
Anatomy
트리거와 그 위에 뜨는 어두운 말풍선. 글 한 줄과 트리거를 가리키는 꼬리.
- 1트리거 · 아이콘 버튼, 잠긴 항목, 잘린 글. 없어도 쓸 수 있는 것에만
- 2컨테이너 · Label/Body #555 채움 · radius 6 · 6 10 · 최대 폭 240 · 그림자 없음
- 3글 · Caption 12 500 · Static/White · 한 줄, 길면 두 줄까지
- 4꼬리 · 6 · 트리거 가운데를 가리킴 · 트리거와 8
Variants
넷. 대부분 Plain이고, 제목이 필요하면 Rich. 트리거가 무엇인지에 따라 Help와 Locked.
Placement
기본은 위. 공간이 없으면 아래, 사이드바처럼 옆으로 열릴 자리면 오른쪽. 꼬리는 항상 트리거 가운데.
Behavior
| 동작 | 규칙 |
|---|---|
| 나타남 | 마우스 올리고 300ms 뒤. 키보드 포커스는 바로. 100ms 페이드 |
| 사라짐 | 마우스가 떠나면 바로. ESC로도. 툴팁 위로 마우스를 옮겨도 유지되지 않아요(안에 누를 게 없으니) |
| 모바일 | 호버가 없어서 탭하면 1.5초 보이고 사라져요. 중요한 설명이면 툴팁 대신 화면에 |
| 내용 | 글만. 링크, 버튼, 이미지는 넣지 않아요. 그게 필요하면 Popover(나중에) |
| 비활성 트리거 | disabled 버튼은 이벤트가 없어서 감싸는 span에 툴팁을 붙여요 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 컨테이너 | 최대 폭 240 · radius 6 | — | Label/Body #555555 · 그림자 없음 | 6 10 · 트리거와 8 |
| 글 | — | Caption 12 500 · 행간 1.5 | Static/White | — |
| Rich | 폭 240 | 제목 12 600 · 설명 12 · 80% | 같음 | 8 12 · 제목 아래 2 |
| 꼬리 | 6 | — | 컨테이너와 같음 | 트리거 가운데 |
| Help 아이콘 | 14 | — | Label/Alternative → 호버 Label/Body | 라벨과 4 |
| 시간 | — | — | — | 지연 300ms · 페이드 100ms |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| content | string · { title, description } | — | 객체면 Rich |
| placement | top · bottom · left · right | top | 공간이 없으면 반대편으로 자동 |
| delay | number | 300 | 호버 지연 ms. 포커스는 무시 |
| children | ReactElement | — | 트리거 하나. disabled면 span으로 감싸 줘요 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| title 속성 | 브라우저 기본 title 툴팁(MonthCalendar, CreditorAccounts)은 늦게 뜨고 스타일이 달라요. 전부 Tooltip으로. |
| 사이드바 잠김 툴팁 | Sidebar 안에 인라인으로 그린 group-hover 툴팁은 Tooltip placement="right"로 교체. |
| 접근성 | role="tooltip", 트리거에 aria-describedby. 아이콘 버튼은 aria-label을 따로 둬요. 툴팁이 라벨을 대신하지 않아요. |
Result
흐름이 끝났을 때의 결과 화면과, 보여줄 것이 없을 때의 대체 화면. 큼직한 아이콘, 한 줄 결론, 다음에 할 일 버튼. 결과는 성공 · 실패 · 처리 중, 대체 화면은 Empty · Error · No access.
위임 계약이 끝났어요
내일부터 회수가 시작돼요. 진행 상황은 대시보드에서 볼 수 있어요.
Anatomy
가운데 정렬 한 열. 톤 색 원 위 흰 아이콘, 제목, 설명, 그리고 버튼 둘까지 나란히. 주 행동은 회색 Neutral, 보조는 Ghost. 결과 화면은 이미 끝난 자리라 오렌지를 쓰지 않아요.
위임 계약이 끝났어요
내일부터 회수가 시작돼요.
- 1아이콘 · 원 64 톤 색 · 흰 글리프 30 선 2 (lucide 기본) · 그림자·글로우 없음
- 2제목 · 22 700 · Label/Title · 한 줄 결론 · 위 24
- 3설명 · Body M 15 · Label/Body · 두 줄까지 · 폭 340 · 위 8
- 4주 행동 · Neutral M · 글자 폭 + 20 · 위 28
- 5보조 행동 · Ghost · 오른쪽에 나란히 · 하나만
Variants
셋. 성공은 다음 할 일로, 실패는 원인과 다시 시도로, 처리 중은 기다리는 동안 무엇을 하면 되는지로 이어요.
계좌가 등록됐어요
상환금은 이 계좌로 들어와요.
서명이 완료되지 않았어요
인증 시간이 지났어요. 처음부터 다시 진행해 주세요.
서류를 검토하고 있어요
보통 1~2일 걸려요. 끝나면 문자로 알려드려요.
Fallback
보여줄 것이 없을 때의 대체 화면도 같은 틀이에요. 아직 없으면 Empty, 못 불러왔으면 Error, 볼 수 없으면 No access. 카드 안에서는 작게.
아직 등록된 채무자가 없어요
첫 채무자를 등록하면 여기에 목록이 보여요.
목록을 불러오지 못했어요
잠시 뒤 다시 시도해 주세요.
관리자만 볼 수 있어요
권한이 필요하면 관리자에게 요청해 주세요.
아직 등록된 채무자가 없어요
첫 채무자를 등록하면 여기에 목록이 보여요.
최근 상환
아직 상환 내역이 없어요
첫 입금이 들어오면 여기에 쌓여요.
Layout
한 화면을 다 쓸 때는 세로 가운데에서 살짝 위. 카드 안에서는 카드 폭 그대로, 모바일에서는 버튼이 바닥에 붙어요.
위임 계약이 끝났어요
내일부터 회수가 시작돼요.
계좌가 등록됐어요
상환금은 이 계좌로 들어와요.
Behavior
| 동작 | 규칙 |
|---|---|
| 이동 | 버튼으로만. 몇 초 뒤 자동으로 넘기지 않아요 |
| 뒤로 가기 | 끝난 흐름으로 돌아가지 않게 히스토리를 바꿔요. 뒤로 가면 대시보드 |
| 처리 중 | 5초마다 상태를 확인해서 끝나면 Success나 Failure로 바뀌어요. 화면을 떠나도 문자로 |
| 실패 | 원인이 사용자 쪽이면 고칠 방법을, 우리 쪽이면 사과와 문의 버튼을 |
| 버튼 | 둘까지. 주 행동 Neutral, 보조 Ghost를 오른쪽에. 모바일에선 세로로 쌓여요. 셋이 필요하면 흐름을 다시 봐요 |
Usage
위임 계약이 끝났어요
내일부터 회수가 시작돼요.
성공
요청이 정상적으로 처리되었습니다.
오류가 발생했습니다
잠시 후 다시 시도해 주세요.
계좌가 등록됐어요
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 컨테이너 | 최대 폭 400 · 가운데 | — | 배경 없음 | 40 24 |
| 아이콘 | 원 64 · 글리프 30 선 2 (sm 48 · 24 / 카드 안 32 · 16) | — | Success #0FA53A · Failure #EB003B · Pending #2768FF · Empty · No access #9A9A9A · 글리프 Static/White | 아래 24 |
| 제목 | — | 22 700 · 자간 -1.5% | Label/Title | — |
| 설명 | 폭 최대 340 | Body M 15 · 행간 1.6 · 두 줄 · 어절 단위 줄바꿈 | Label/Body | 위 8 |
| 버튼 | M 36 · 글자 폭 + 20 | — | Neutral · 보조 Ghost 옆에 · Primary 안 씀 | 위 28 · 사이 8 |
| 모바일 | 버튼 폭 100% · 세로로 | — | — | 바닥 고정 · 좌우 20 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| status | success · failure · pending · empty · error · forbidden | — | 아이콘과 색이 함께 정해져요. empty·forbidden은 회색 |
| size | md · sm | md | 페이지 · 카드 안(아이콘 32, 제목 15) |
| title | string | — | 필수. 한 줄 결론 |
| description | string | — | 두 줄까지 |
| action | { label, onClick · to } | — | 주 행동. Neutral(회색). 결과 화면엔 오렌지가 없어요 |
| secondary | { label, onClick · to } | — | 보조 행동 하나. Ghost |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| 완료 화면 여러 벌 | 계좌 등록, 서명, 플랜 제안 완료 화면이 각자 CheckCircle과 문구를 그려요. Result 하나로. |
| 그라데이션 배경 | EmptyOnboarding의 from-surface 그라데이션은 쓰지 않아요. 배경은 페이지 그대로. |
| EmptyOnboarding | 빈 화면을 따로 그리던 EmptyOnboarding은 Result status="empty"로. 카드 안 빈 상태는 size="sm". |
Skeleton
데이터가 오는 동안 진짜 내용 자리에 놓는 회색 덩어리. 빈 화면이나 스피너 대신 곧 나올 것의 모양을 먼저 보여줍니다. 내용이 오면 같은 자리에서 바뀌어요.
Anatomy
조각은 셋뿐이에요. 글 줄, 덩어리, 원. 이 셋을 진짜 화면과 같은 자리에 같은 크기로 놓습니다.
- 1글 줄 · 높이는 글자 크기 − 4 · radius 6 · 폭 40 · 60 · 90% 중 하나
- 2덩어리 · 카드, 이미지, 표 자리 · 진짜와 같은 radius
- 3원 · 아바타, 아이콘 자리 · 진짜와 같은 크기
Variants
자주 쓰는 화면 넷을 미리 만들어 둡니다. 새 화면은 셋 조각으로 조합하되, 진짜 레이아웃에서 한 줄도 어긋나지 않게.
Sizes
글 줄 높이는 글자 크기에서 4를 뺀 값. 그래야 진짜 글이 들어왔을 때 줄 위치가 그대로예요. 폭은 셋 중 하나만 씁니다.
Behavior
| 동작 | 규칙 |
|---|---|
| 나타남 | 요청 후 300ms가 지나도 안 오면 그때 보여요. 빨리 오는 데이터엔 깜빡이지 않게 |
| 머무름 | 한 번 보이면 최소 500ms. 보이자마자 사라지면 더 어수선해요 |
| 움직임 | 왼쪽에서 오른쪽으로 옅은 빛이 지나가는 shimmer 1.6s. 화면 전체가 같은 박자로 |
| 바뀜 | 내용이 오면 같은 자리에서 페이드 150ms. 높이가 달라 화면이 튀면 스켈레톤 크기가 틀린 거예요 |
| 범위 | 지금 기다리는 영역만. 머리글, 제목, 탭처럼 이미 아는 건 진짜로 그려요 |
| 개수 | 목록은 최대 5행. 그 아래는 비워요 |
Usage
출금 계좌
계좌 인증
Specification
| 부분 | 크기 | 색 | 움직임 | 여백 |
|---|---|---|---|---|
| 글 줄 | 높이 글자 − 4 · radius 6 | Fill/Normal #F0F0F0 | shimmer → #F8F8F8 | 줄 사이 8 · 폭 40 · 60 · 90% |
| 덩어리 | 진짜와 같음 | Fill/Normal | 같음 | 진짜와 같음 |
| 원 | 진짜와 같음 | Fill/Normal | 같음 | — |
| shimmer | 폭 200% 그라데이션 | #F0F0F0 → #F8F8F8 → #F0F0F0 | 1.6s linear 무한 | — |
| 시간 | — | — | 지연 300ms · 최소 500ms · 교체 150ms | — |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| variant | text · block · circle | text | 조각 하나 |
| width · height | number · '40%' · '60%' · '90%' | '60%' · 12 | text는 폭 셋 중 하나 |
| lines | 1~3 | 1 | text 여러 줄. 마지막 줄은 60% |
| radius | number | 6 · block 12 · circle 50% | 진짜 요소와 같게 |
| pattern | kpi · table · list · card | — | <SkeletonPattern>. rows로 반복 수(최대 5) |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| animate-pulse | Tailwind 기본 pulse(투명도 깜빡임)는 쓰지 않아요. shimmer 하나로 통일. |
| 로딩 스피너 | 화면 가운데 스피너 하나로 기다리게 하던 페이지들은 Skeleton으로. 스피너는 버튼 안(loading)에서만. |
| aria | 감싸는 영역에 aria-busy="true", 스켈레톤 자체는 aria-hidden. 내용이 오면 aria-busy 해제. |
| reduced motion | 움직임 줄이기 설정이면 shimmer를 끄고 색만. |
Toast
방금 한 일의 결과를 화면 아래에서 잠깐 알려주는 한 줄. 3초 뒤 스스로 사라지고, 흐름을 막지 않아요. 답을 받아야 하면 Alert, 남아 있어야 하면 Banner.
Anatomy
어두운 반투명 알약에 흰 글 한 줄. 필요하면 앞에 아이콘, 뒤에 행동 하나.
- 1컨테이너 · Static/Black 86% + blur 8 · radius 10 · 10 16 · 최대 폭 360 · 화면 아래 가운데, 바닥에서 32
- 2아이콘 · 16 · 성공 · 실패에만 · 어두운 배경용 밝은 톤
- 3글 · Label S 13 600 · Static/White · 한 줄, 길면 두 줄까지
- 4행동 · 13 700 · Primary 밝은 톤 · 하나만 · 있으면 5초
Variants
넷. 대부분은 글만 있는 Default. 결과가 좋고 나쁨이 중요하면 아이콘, 되돌릴 수 있으면 행동, 설명이 꼭 필요하면 두 줄.
Placement
화면 아래 가운데, 바닥에서 32. 사이드바가 있어도 콘텐츠 영역이 아니라 화면 기준이에요. 모바일에서는 바닥 탭 위 16.
Behavior
| 동작 | 규칙 |
|---|---|
| 나타남 | 아래에서 12 올라오며 페이드 200ms |
| 사라짐 | 3초. 행동이 있으면 5초. 마우스를 올리면 멈추고, 떠나면 다시 세요. 누르면 바로 |
| 겹침 | 한 번에 하나. 새 토스트가 오면 이전 것은 바로 바뀌어요. 쌓지 않아요 |
| 실패 | 다시 시도가 필요한 실패는 Toast가 아니라 Banner나 Alert. Toast 실패는 "내려받지 못했어요"처럼 가벼운 것만 |
| 접근성 | role="status" aria-live="polite". 행동 버튼은 Tab으로 갈 수 있고, 포커스되면 사라지지 않아요 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 컨테이너 | 최대 폭 360 · radius 10 | — | Static/Black 86% + blur 8 · 그림자 0 8 24 18% | 10 16 · 두 줄 12 16 · 바닥 32 |
| 글 | — | Label S 13 600 · 두 줄형 설명 12.5 400 | Static/White · 설명 80% | 아이콘과 10 |
| 아이콘 | 16 | — | 성공 #7BE495 · 실패 #FF6B8A | — |
| 행동 | — | 13 700 | Primary 밝은 톤 #FF8A47 | 글과 12 |
| 시간 | — | — | — | 등장 200ms · 유지 3s (행동 5s) |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| message | string | — | 한 줄. "~했어요" |
| tone | neutral · success · danger | neutral | 아이콘이 붙어요 |
| description | string | — | 두 줄형 |
| action | { label, onClick } | — | 하나. 있으면 5초 |
| duration | number | 3000 · 5000 | 바꾸지 않는 게 기본 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| alert() | 브라우저 alert로 알리던 곳(복사 완료, 저장 완료)은 전부 toast()로. |
| 성공 모달 | "저장되었습니다" 모달은 Toast로. Modal 페이지의 don't. |
| 위치 | fixed, 화면 기준. 사이드바 폭을 빼고 가운데 맞추지 않아요. |
Loading
기다리는 동안 무언가 하고 있다는 신호. 화면 구조를 알면 Skeleton, 버튼이나 작은 영역이면 Spinner. 둘을 같이 쓰지 않아요.
Anatomy
회색 트랙 위를 도는 진한 호. 옆에 글이 붙으면 무엇을 기다리는지 말해요.
- 1트랙 · 원 20 (S 16 · L 32) · 선 2 (L 3) · Line/Normal
- 2호 · 4분의 1 · Label/Title · 0.8초에 한 바퀴 · 버튼 안에서는 Static/White
- 3글 · Body S 14 · Label/Alternative · "~하는 중" · 있어도 없어도
Variants
넷. 버튼을 눌러 기다릴 땐 In button, 한 줄로 알릴 땐 Inline, 카드나 영역 하나면 Area, 화면 전체를 막아야만 하면 Overlay.
Sizes
Behavior
| 동작 | 규칙 |
|---|---|
| 나타남 | 300ms가 지나도 안 끝나면 그때. 빨리 끝나는 일엔 깜빡이지 않게 |
| 버튼 | 누르는 순간 로딩. 같은 폼의 다른 버튼도 비활성. 끝나면 Toast나 화면 전환 |
| 오래 걸리면 | 3초 넘으면 글을 붙여요("서명을 확인하는 중"). 10초 넘으면 "시간이 걸리고 있어요" + 취소 |
| Skeleton과 | 목록, 카드, 표처럼 모양을 아는 건 Skeleton. Spinner는 행동의 결과나 모양을 모르는 작은 영역 |
| 움직임 줄이기 | 설정이 켜져 있으면 회전 대신 호가 천천히 깜빡여요 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 움직임 |
|---|---|---|---|---|
| Spinner | S 16 · M 20 · L 32 · 선 2 · 2 · 3 | — | 트랙 Line/Normal · 호 Label/Title · 버튼 안 Static/White 35% / 100% | 0.8s linear 무한 |
| Inline 글 | — | Body S 14 | Label/Alternative | 스피너와 10 |
| Overlay | 영역 전체 | 13 | Static/White 70% | 등장 150ms |
| 시간 | — | — | — | 지연 300ms · 글 3s · 취소 10s |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| size | sm · md · lg | md | 16 · 20 · 32 |
| label | string | — | 옆에 글. 없어도 aria-label "불러오는 중" |
| delay | number | 300 | 이 시간 안에 끝나면 안 보여요 |
| Button loading | boolean | false | Button의 prop. 스피너 + 비활성 + 라벨 유지 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| Loader2 아이콘 | lucide Loader2에 animate-spin을 붙인 곳이 여러 벌이에요. Spinner 하나로. |
| 페이지 가운데 스피너 | 목록 페이지의 전체 스피너는 SkeletonPattern으로 바꿔요. |
| aria | role="status" aria-live="polite" aria-label="불러오는 중". 오버레이는 aria-busy를 영역에. |
Navigation
왼쪽 사이드바 256 고정. 지금 있는 곳만 오렌지, 나머지는 모두 회색이에요. 좁은 화면에서는 아래 탭으로 바뀝니다.
Anatomy
로고, 그룹 라벨, 항목, 그리고 맨 아래 계정. 항목은 아이콘 자리와 라벨, 필요하면 오른쪽에 개수.
- 1로고 영역 · 높이 56 · 왼쪽 정렬
- 2그룹 라벨 · Caption 11 600 · Label/Alternative · 대문자 · 자간 .08em
- 3활성 항목 · Primary/Normal 글자와 아이콘 · Fill/Normal 배경 · 600
- 4항목 · 높이 38 · 아이콘 16 in 28 · Label M 14 500 · Label/Body · 개수는 Count 배지
- 5계정 · 아바타 28 · 이름 13 600 · 역할 Caption · 누르면 메뉴
Variants
넷. 데스크톱은 Sidebar, 모바일은 Bottom tab, 사이드바가 없는 온보딩 화면은 Top bar, 계정을 누르면 Menu.
States
항목의 상태. 호버는 아주 옅은 회색이고 오렌지는 활성에만 씁니다. 권한이 없으면 흐리게 두고 이유를 툴팁으로.
Layout
사이드바 256, 위에 붙는 헤더 64, 나머지가 콘텐츠. 콘텐츠는 회색 면에 안쪽 여백 40 32이고 최소 폭 1080 아래로는 모바일 구조로 바뀝니다.
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| Sidebar | 폭 256 · 높이 100% | — | Background/Normal · 오른쳑 Line/Alternative | 로고 56 · 목록 16 12 |
| 그룹 라벨 | — | Caption 11 600 · 대문자 · 자간 .08em | Label/Alternative | 12 12 4 · 첫 그룹 위 8 |
| 항목 | 높이 38 · radius 8 | Label M 14 500 | Label/Body · 아이콘 Label/Alternative | 좌우 12 · 아이콘과 10 · 항목 사이 4 |
| Hover | — | — | Static/Black 4% | — |
| Active | — | 600 | Primary/Normal 글자와 아이콘 · Fill/Normal 배경 | — |
| 개수 | Count 배지 20 | Caption 11 700 tabular | Primary/Normal · 99+ | 오른쪽 끝 |
| 계정 | 아바타 28 | 이름 13 600 · 역할 Caption | 위 Line/Alternative | 12 12 |
| Bottom tab | 높이 56 + safe area | Caption 11 500 | Label/Alternative → 활성 Primary/Normal · 위 Line/Alternative | 아이콘 22 · 라벨 위 4 |
| Top bar | 높이 64 | 이름 15 600 | Background/Normal | 좌우 24 |
| Menu | 폭 200 · radius 12 | Body S 14 | Elevation Dropdown · 로그아웃 Danger | 항목 10 16 · 위아래 4 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| groups | { label, items: NavItem[] }[] | — | 그룹과 항목. 라벨 없는 그룹도 가능 |
| NavItem | { to, label, icon, count?, locked?, lockReason? } | — | icon은 lucide 컴포넌트. count는 0이면 숨김 |
| account | { name, role, menu: MenuItem[] } | — | 맨 아래 계정과 눌렀을 때 메뉴 |
| end | boolean | false | NavLink end. 대시보드처럼 루트 경로에만 true |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| 인라인 색 | 지금 NavLink는 style={{ color: '#52525b' }}처럼 색을 직접 넣어요. 클래스로 옮기고 #52525b → Label/Body, #8A9099 → Label/Alternative, #F4F4F5 → Fill/Normal. |
| 로고 영역 80 | 80에서 56으로. 헤더 64와 같은 줄에 맞추려면 56 + 여백 8. |
| 우선 안내 툴팁 | 사이드바 안의 온보딩 말풍선(border-2 검정)은 Navigation 밖의 패턴이에요. 나중에 Tooltip으로. |
| 모바일 드로어 | 오른쪽에서 나오는 280 드로어는 Bottom tab으로 대체. 드로어는 메뉴가 다섯을 넘을 때만. |
Menu
버튼이나 더보기를 누르면 열리는 행동 목록. 항목은 동사로 짧게, 되돌릴 수 없는 행동은 맨 아래 Danger로. 값을 고르면 Select, 화면을 옮기면 Navigation이에요.
Anatomy
트리거 아래 6 떨어진 흰 컨테이너. 안은 항목이고, 무리를 나눌 땐 구분선. 위험한 행동은 구분선 아래 맨 끝에.
- 1트리거 · 아이콘 버튼 32 또는 Neutral 버튼. 열려 있으면 Fill/Normal
- 2컨테이너 · 폭 180~280 · radius 16 · Elevation Dropdown · 안쪽 8 · 트리거와 6
- 3항목 · 높이 44 · 14.5 · Label/Title · radius 10 · 좌우 12
- 4앞 아이콘 · 16 · Label/Alternative · 있으면 모든 항목에
- 5구분선 · Line/Alternative 1px · 위아래 4 · 좌우 8
- 6위험 항목 · Danger 글자와 아이콘 · 구분선 아래 맨 끝에 하나
Variants
넷. 대부분은 Action이고, 항목이 다섯을 넘으면 Sections로 나눠요. Check는 지금 고른 상태를 함께 보여줄 때.
Sizes
항목 높이 둘. 기본 40, 표의 행마다 붙는 더보기 메뉴처럼 좁은 곳은 36.
States
항목의 상태 넷. 호버는 Fill/Normal, 위험은 Danger 글자에 호버 Danger 6%.
Placement
트리거 바로 아래, 왼쪽을 맞춰 열립니다. 트리거가 오른쪽 끝에 있으면 오른쪽을 맞추고, 아래 공간이 없으면 위로.
Behavior
| 동작 | 규칙 |
|---|---|
| 열기 | 클릭. 호버로 열지 않아요. 열리면 트리거가 Fill/Normal로 눌린 상태 |
| 닫기 | 항목을 고르면, ESC, 바깥 클릭. 셋 다 같은 결과 |
| 키보드 | ↑↓로 이동, Enter로 실행. 열리면 첫 항목에 포커스 |
| 겹침 | 한 번에 하나. 다른 메뉴가 열리면 앞 메뉴는 닫혀요. 메뉴 안에 메뉴는 두지 않아요 |
| 위험 항목 | 고르면 바로 실행하지 않고 Modal Alert로 한 번 물어요 |
| 모바일 | 640 미만에서 Bottom sheet. 항목 높이 48 |
Usage
Specification
| 부분 | 크기 | 글 | 색 · 그림자 | 여백 |
|---|---|---|---|---|
| 컨테이너 | 폭 180~280 · radius 16 | — | Background/Normal · Elevation Dropdown | 안쪽 8 · 트리거와 6 |
| 항목 M | 높이 44 · radius 10 | 14.5 | Label/Title · 호버 Fill/Normal | 좌우 12 · 아이콘과 10 |
| 항목 S | 높이 38 · radius 8 | 13.5 | 같음 | 좌우 10 · 컨테이너 안쪽 6 · radius 12 |
| 아이콘 | 16 | — | Label/Alternative · 위험 Danger | — |
| 체크 | 14 | 고른 항목 600 | Primary 글자와 체크 | 왼쪽 · 안 고른 항목도 자리 16 비움 |
| 구분선 | 1 | — | Line/Alternative | 위아래 4 · 좌우 8 |
| 섹션 라벨 | — | 12.5 500 | Label/Alternative | 8 12 6 |
| 위험 항목 | — | — | Danger · 호버 Danger 6% | 구분선 아래 |
| 트리거 | 아이콘 버튼 32 · radius 8 | — | 열리면 Fill/Normal | — |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| trigger | ReactNode | — | 버튼이나 아이콘 버튼. 열림 상태는 Menu가 넘겨줘요 |
| items | { label, icon?, onSelect, tone?: 'danger', disabled?, checked? }[] | — | 배열 안의 'divider'로 구분선, { label }만 있으면 섹션 라벨 |
| size | md · sm | md | 40 · 36 |
| align | start · end | start | 트리거 기준 왼쪽 · 오른쪽 맞춤. 위아래는 공간 보고 자동 |
| width | number | 200 | 160~280 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| 드롭다운 세 벌 | OnboardingHeader, ViewToggle, Sidebar 계정 메뉴가 각자 div로 그려요. Menu 하나로 모으고 items만 넘겨요. |
| border + shadow | 지금 드롭다운은 테두리와 그림자를 같이 써요. Elevation Dropdown 그림자만. |
| role | 컨테이너 role="menu", 항목 role="menuitem" 또는 menuitemradio(체크). 트리거에 aria-expanded. |
| Select와 구분 | 폼 값이 되는 선택은 Select. Menu의 check는 정렬, 보기 방식처럼 화면 상태만. |
Stepper
여러 단계로 이어지는 흐름을 보여주는 표시. 두꺼운 진행 바 안에 단계 점을 놓고, 지금까지 온 만큼 옅은 오렌지로 채웁니다. 순서만 안내할 때는 List. 단계는 셋에서 다섯.
Anatomy
두꺼운 트랙 안에 단계 점, 그 아래 라벨. 시작부터 지금 점까지 옅은 오렌지로 채우고, 지금 점만 진하게.
- 1트랙 · 높이 12 · radius 6 · Fill/Normal · 폭 100%
- 2채움 · Primary 7% → 30% 그라데이션 · 시작부터 지금 점까지
- 3끝난 점 · 8 · Static/White · Primary 35% 테두리 · 그림자 살짝
- 4지금 점 · 14 · Primary · 링 4 Primary 22%
- 5남은 점 · 8 · Static/White · Line/Normal 테두리
- 6라벨 · Label S 13 · 트랙 아래 12 · 지금만 Label/Title 700 · 양끝은 끝에 맞춤
Variants
넷. 대부분은 Line이고, 단계 번호가 중요하면 Pill. 할 일을 하나씩 끝내는 화면은 Vertical, 순서만 설명하는 안내는 List.
List 글 조합
List의 제목과 설명 크기는 셋 중 하나. 기본은 15 + 13, 큼직하게 보일 자리엔 17, 촘촘히 넣을 자리엔 12.
States
단계 하나의 상태 넷. 순서대로 흘러가고, 검증에 걸린 단계만 Danger.
Layout
온보딩에서는 제목 줄 오른쪽에 폭 320. 페이지 폭을 다 쓸 때는 카드 안 맨 위에 폭 100%. 좁은 화면에서도 같은 Line, 라벨은 지금 단계만 남겨요.
Behavior
| 동작 | 규칙 |
|---|---|
| 이동 | 순서대로만 앞으로. 끝난 단계는 라벨을 눌러 돌아갈 수 있고, 남은 단계는 누를 수 없어요 |
| 채움 | 시작 점에서 지금 점까지. 단계가 바뀌면 300ms에 걸쳐 늘어나요 |
| 돌아가기 | 끝난 단계로 돌아가 고치면 그 뒤 단계는 다시 확인. 채움은 유지 |
| 단계 수 | 3~5. 여섯이 넘으면 묶어서 줄이거나 Vertical로 |
| 라벨 | 명사 2~4자. "채권 정보", "플랜 제시". 문장이나 동사는 쓰지 않아요 |
| 모바일 | 640 미만에서도 Line 그대로. 라벨은 지금 단계만 남기고 나머지는 숨겨요 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| Line 트랙 | 12 · radius 6 · 폭 100% | — | Fill/Normal · 채움 Primary 7% → 30% 그라데이션 | 라벨과 12 · 점 안쪽 6 |
| Line 점 | 8 · 지금 14 | — | Done 흰 + Primary 35% 테두리 · Upcoming 흰 + Line/Normal · Current Primary + 링 4 22% | 트랙 가운데 |
| Pill 트랙 | 36 · radius 18 | — | Fill/Normal · 지나온 구간 Primary 6% → 24% 그라데이션 | 안쪽 4 |
| Pill 원 | 28 | 숫자 12 700 · 체크 13 | Background/Normal · Done 체크 Primary · Current Primary + 링 4 20% · Error Danger | — |
| 라벨 | — | Label S 13 500 · Current 700 | Label/Alternative · Current Label/Title · Done Label/Body | 점 아래 10 · 양끝 정렬 |
| Vertical | 원 28 · 바 4 | 제목 14 600 · 설명 12.5 | Pill 원과 같음 | 원과 글 12 · 단계 사이 20 |
| List | 원 28 · 선 2 | A 15 600 + 13 · B 17 700 + 13 · C 15 600 + 12 | 원 Fill/Normal · 아이콘 원 Primary 10% | 행 위아래 10 · 원과 글 12 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| steps | { key, label, description?, icon? }[] | — | 3~5개. description은 Vertical과 List에서만 |
| current | key | — | 지금 단계. 앞은 Done, 뒤는 Upcoming으로 자동. List에선 무시 |
| variant | line · pill · vertical · list | line | 형태 |
| texts | A · B · C | A | List 제목·설명 크기. 15+13 · 17+13 · 15+12 |
| steps[].right | 'chevron' · { label, onClick } | — | List 오른쪽. chevron 또는 버튼 하나 |
| error | key[] | [] | 검증에 걸린 단계 |
| onStepClick | (key) => void | — | Done 단계에서만 불려요 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| OnboardingStepper | 흐름 판단(채권자·채무자·법인)은 그대로 두고, 그리는 부분만 Stepper variant="line"으로. 원+선 마크업은 지워요. |
| 모바일 조각 바 | sm:hidden으로 따로 그리던 조각 바는 없애요. Line이 그대로 내려가고 라벨만 줄어요. |
| role | nav aria-label="진행 단계", 지금 단계 라벨에 aria-current="step". |
Pagination
긴 목록을 페이지로 나눠 옮겨 다니는 조작. 표 아래 가운데에 번호 다섯 개와 양끝 화살표. 20건이 넘을 때만 쓰고, 무한 스크롤은 쓰지 않아요.
Anatomy
이전 화살표, 번호 다섯, 말줄임, 마지막 번호, 다음 화살표. 필요하면 오른쪽에 전체 개수.
- 1이전 · 아이콘 버튼 32 Ghost · 첫 페이지에선 비활성
- 2번호 · 32 정사각 Ghost · Label S 13 500 · 지금 페이지 앞뒤로 둘씩, 다섯 개
- 3지금 페이지 · Primary 채움 · Static/White 700
- 4말줄임 · 24 · Label/Alternative · 번호가 이어지지 않을 때만
- 5다음 · 마지막 페이지에선 비활성
- 6전체 · Caption 12 tabular · Label/Alternative · 왼쪽 여백 12
Variants
넷. 표 아래는 Default, 개수까지 알려주면 With total, 좁은 자리는 Compact, 한 페이지에 몇 건인지 바꿀 수 있으면 Page size.
States
Behavior
| 동작 | 규칙 |
|---|---|
| 번호 | 지금 페이지 앞뒤 둘씩 다섯 개. 첫 페이지와 마지막은 항상 보이고, 이어지지 않으면 사이에 말줄임 |
| 이동 | 페이지가 바뀌면 표 맨 위로 스크롤. 선택한 행과 필터는 유지 |
| URL | ?page=3처럼 쿼리에. 새로 고쳐도, 뒤로 가도 그 페이지 |
| 개수 | 한 페이지 20건 기본. 전체가 20 이하면 페이지네이션 자체를 그리지 않아요 |
| 키보드 | Tab으로 번호 이동, Enter. ←→는 이전·다음 |
| 모바일 | 640 미만에서 Compact로 자동 |
Usage
| 채무자 | 원금 |
|---|---|
| 김리바 | 8,400,000 |
| 이바운 | 3,200,000 |
| 채무자 | 원금 |
|---|---|
| 김리바 | 8,400,000 |
Specification
| 부분 | 크기 | 글 | 색 | 여백 |
|---|---|---|---|---|
| 번호 · 화살표 | 32 정사각 · radius 8 | Label S 13 500 tabular | Ghost · Label/Body · 호버 Fill/Normal | 사이 4 |
| 지금 페이지 | 같음 | 700 | Primary · Static/White | — |
| 말줄임 | 폭 24 | 13 | Label/Alternative | — |
| 전체 | — | Caption 12 tabular | Label/Alternative | 왼쪽 12 |
| Compact | 화살표 32 · 글 사이 8 | 13 · 지금 600 | Label/Title · 전체 Label/Alternative | — |
| 자리 | 표 아래 · 가운데 | — | 표와 같은 카드 | 위아래 14 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| page · onChange | number · fn | — | 1부터 |
| total · pageSize | number | — · 20 | 전체 건수와 페이지당 건수. 페이지 수는 여기서 계산 |
| showTotal | boolean | false | "지금 / 전체 · n건" |
| compact | boolean | auto | 640 미만이면 자동 |
| pageSizeOptions | number[] | — | 주면 오른쪽에 Select S |
| syncQuery | string | 'page' | URL 쿼리 이름 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| Pagination.tsx | 지금 컴포넌트는 border 버튼과 "이전/다음" 글자예요. Ghost 아이콘 버튼과 말줄임 규칙으로 바꿔요. |
| aria | nav aria-label="페이지", 지금 페이지에 aria-current="page", 화살표에 aria-label. |
Segmented control
같은 자리의 내용을 두세 갈래로 바꿔 보는 조작. 회색 트랙 안에서 흰 조각이 고른 쪽으로 미끄러져요. 페이지가 바뀌면 Tabs, 여럿을 고르면 Chip, 켜고 끄면 Switch.
Anatomy
회색 트랙, 그 안의 조각들, 고른 조각 뒤의 흰 판. 판만 움직이고 글자는 자리를 지켜요.
- 1트랙 · 높이 40 · radius 12 · Fill/Normal · 안쪽 4
- 2조각 · 높이 32 · 좌우 16 · Label M 14 500 · Label/Alternative · 호버 Label/Body
- 3고른 조각 · 뒤에 흰 판 radius 9 + 그림자 살짝 · 글자 Label/Title 600 · 판은 0.25s 미끄러짐
Variants
넷. 글자만 있는 Default가 기본이고, 뜻이 아이콘으로 더 빨리 읽히면 With icon, 개수를 알려주면 With count, 폼 안에서 폭을 채우면 Full width.
Sizes
States
Behavior
| 동작 | 규칙 |
|---|---|
| 고르기 | 누르면 바로 바뀌어요. 저장 버튼 없음. 흰 판이 0.25s에 걸쳐 옮겨가고 글자 색은 0.2s |
| 개수 | 2~5 조각. 여섯이 넘거나 라벨이 길면 Tabs나 Select |
| 항상 하나 | 고른 조각이 없는 상태는 없어요. 처음엔 첫 조각 |
| 키보드 | Tab으로 들어가고 ←→로 옮기면 바로 골라져요. role="radiogroup" |
| 유지 | 보기 방식처럼 취향이면 기억(localStorage), 필터면 URL 쿼리 |
| Tabs와 | 같은 데이터를 다르게 보면 Segmented, 다른 내용으로 넘어가면 Tabs. 화면에 둘 다 있으면 Tabs가 위 |
Usage
Specification
| 부분 | 크기 | 글 | 색 | 움직임 |
|---|---|---|---|---|
| 트랙 | S 32 · M 40 · L 44 · radius 12 (S 10) · 안쪽 4 | — | Fill/Normal | — |
| 조각 | 28 · 32 · 36 · 좌우 12 · 16 · 20 | 13 · 14 · 15 · 500 | Label/Alternative · 호버 Label/Body | 글자 색 .2s |
| 흰 판 | 조각과 같음 · radius 9 (S 7) | 고른 글자 600 | Background/Normal · 그림자 0 1 3 8% | left · width .25s cubic-bezier(.4,0,.2,1) |
| 개수 | — | 12 tabular | Label/Alternative | 글자와 4 |
Props
| Prop | 값 | 기본 | 설명 |
|---|---|---|---|
| value · onChange | T · fn | — | 항상 하나가 골라져 있어요 |
| options | { value, label, icon?, count?, disabled? }[] | — | 2~5개 |
| size | sm · md · lg | md | 32 · 40 · 44 |
| full | boolean | false | 폭 100%, 조각 균등 |
쓰기
클래스
주의
| 항목 | 설명 |
|---|---|
| ViewToggle | 보기 방식을 드롭다운으로 바꾸던 ViewToggle은 Segmented(With icon)로. 두 갈래면 드롭다운이 과해요. |
| role | radiogroup + radio, aria-checked. 버튼이 아니라 라디오로 읽혀야 "하나만 고른다"가 전달돼요. |
| 움직임 줄이기 | prefers-reduced-motion이면 판이 바로 옮겨가요. |
페이지 구성
모든 화면은 같은 순서로 시작해요. 제목, 한 줄 설명, 요약, 목록 순으로.
페이지 헤더
섹션 사이 간격은 20px. 인사형 제목은 “안녕하세요, 김리바님” + 오늘 날짜를 부제로 둡니다.
빈 화면
처음 온 사용자가 가장 먼저 보는 화면이에요. 사과하지 말고, 다음에 할 일 하나만 크게 보여줍니다.
첫 채권을 등록하면 상환 일정과 회수 현황을 자동으로 따라가요.
상태별 화면
| 상태 | 표현 |
|---|---|
| 로딩 | 스켈레톤(회색 #F4F4F5 블록). 스피너는 버튼 안에서만 |
| 빈 결과 | 한 문장 + 되돌리는 행동(필터 초기화) |
| 오류 | 무슨 일이 있었는지 + 다시 시도. 코드·스택은 보여주지 않아요 |
| 권한 없음 | 메뉴는 보이되 흐리게 + 툴팁으로 이유(“관리자만 신청할 수 있어요”) |
| 성공 | 토스트 한 줄. 화면을 막지 않아요 |
문구
돈과 법이 걸린 화면이에요. 친근함보다 정확함이 먼저고, 정확한 다음에 짧게 씁니다.
기본
| 항목 | 규칙 |
|---|---|
| 말투 | 존댓말 해요체. “등록되었습니다”보다 “등록했어요”. 단, 법적 고지·동의서는 문어체 그대로 |
| 용어 | 채권자 / 채무자 / 상환 / 회수 / 위임 / 연체. 화면마다 다르게 부르지 않아요 |
| 주어 | 사용자가 한 일은 사용자 기준으로. “시스템이 처리했습니다” ✕ |
| 길이 | 버튼 2~6자, 설명 한 문장, 도움말 두 줄 이내 |
숫자 표기
| 대상 | 표기 | 비고 |
|---|---|---|
| 금액 | 12,340,000원 | 축약·소수점 없이 |
| 건수 | 148명 · 7건 | 단위 붙여쓰기 |
| 비율 | 62% | 필요할 때만 소수점 한 자리(62.5%) |
| 날짜 | 2026.09.15 | 요일이 필요하면 2026.09.15 (화) |
| 기간 | 2026.09.15 ~ 10.14 | 같은 해면 뒤쪽 연도 생략 |
| 남은 기간 | D-7 | 당일은 D-day |
예시
이렇게
- 계좌를 등록하면 상환금이 자동으로 들어와요.
- 9월 25일에 출금될 예정이에요.
- 10자리 숫자만 입력해 주세요.
- 관리자만 신청할 수 있어요.
이건 피해요
- 처리 중 오류가 발생하였습니다 (E-500)
- 유효하지 않은 값입니다
- 정말로 삭제하시겠습니까?!
- Loading… 처럼 영문 섞기
로고
심볼과 워드마크, 그리고 쓰면 안 되는 방식이에요. 워드마크는 검정 한 가지, 색은 심볼 안의 네 조각에만 들어갑니다.
파일
심볼의 색
심볼은 검정 조각 열두 개와 색 조각 네 개, 모두 16조각으로 되어 있어요. 이 네 색은 로고 전용이고, 화면의 UI 색으로 가져다 쓰지 않습니다. 화면 색은 Semantic에서 고르세요.
| 자리 | 값 | 비고 |
|---|---|---|
| 왼쪽 | #FF5900 | 비즈의 primary와 같은 오렌지. 유일하게 UI와 공유하는 색 |
| 위 | #009DFF | 로고 전용 블루 (UI의 tertiary와 다른 값) |
| 오른쪽 | #C7F64F | 로고 전용 라임 |
| 아래 | #C0FFF9 | 로고 전용 민트 |
| 나머지 | #000000 | 심볼의 획과 워드마크 |
규칙
| 규칙 | 내용 |
|---|---|
| 최소 크기 | 심볼 20px, 조합 로고 높이 24px 이상. 그보다 작아지면 색 조각이 뭉개져요 |
| 여백 | 사방으로 심볼 높이의 절반(19px 기준 약 10px) 이상 비웁니다 |
| 배경 | 흰색·아주 옅은 회색 위에만. 사진이나 색이 있는 면 위에는 흰 판을 깔고 올려요 |
| 어두운 배경 | 워드마크와 심볼의 검정 조각만 #FFFFFF로 교체하고, 색 네 조각은 그대로 둡니다 |
| 파비콘 | 탭 아이콘은 워드마크의 a 글리프(favicon.svg)를 씁니다. 16px에서는 심볼의 갈래가 뭉개지기 때문이에요. 본문·헤더에는 쓰지 않아요 |
| 금지 | 비율 변경, 회전, 그림자·그라디언트, 색 조각 교체, 심볼과 워드마크 간격 임의 조정 |
코드로 쓰기
SVG 파일을 그대로 쓰는 것이 기본이에요. 색을 바꿔야 하면 currentColor로 바꾼 사본을 따로 두지 말고, 어두운 배경용 파일을 하나 더 만들어 씁니다.
AI 스킬
ARC 규칙을 AI 코딩 도구가 알아서 따르게 하는 설명서 파일. 한 번 설치하면 "ARC", "리바운드", 템플릿 URL이 나오는 작업에서 자동으로 적용돼요. 개발자는 문서 URL만 붙이면 됩니다.
설치
개인은 홈 폴더에, 팀은 rebound-biz 저장소 안에 두고 커밋해요. 저장소에 두면 설치 없이 모두 같은 버전을 쓰고, 규칙이 바뀌면 PR 하나로 갱신돼요.
쓰는 법
| 단계 | 설명 |
|---|---|
| 1 고르기 | 만들 화면과 가장 가까운 컴포넌트나 템플릿 페이지의 URL을 복사해요 |
| 2 붙이기 | Claude Code에 "이 URL로 ○○ 페이지 만들어 줘". 스킬이 같은 주소의 .md를 먼저 읽어요 |
| 3 확인 | 구조 → 토큰 → 컴포넌트 순서로 만들고, 끝에 체크리스트로 스스로 점검. 구조가 요청과 다르면 먼저 물어봐요 |
| 갱신 | 같은 명령을 다시 실행하면 덮어써요. 스킬은 작업 전 최신본 버전을 확인하도록 되어 있어요 |
함께 쓰는 파일
| 파일 | 용도 | 주소 |
|---|---|---|
| SKILL.md | 규칙 설명서. 절대 규칙 아홉, 토큰 표, 글자·레이아웃, 컴포넌트 29개 요약, 체크리스트 | /skill/SKILL.md |
| arc.css | CSS 변수 토큰 | /tokens/arc.css |
| tailwind.preset.js | Tailwind 프리셋. presets: [require('./tailwind.arc.preset')] | /tokens/tailwind.preset.js |
| arc.json | 기계용 토큰(색·간격·라운드·그림자·글자·레이아웃·모션) | /tokens/arc.json |
| 설치 안내 | 공유용 한 장짜리 페이지 | /skill/ |
왜 스킬인가
보안 장치가 아니라 설명서예요. 없어도 URL을 붙이면 페이지는 만들어지지만 규칙을 자꾸 놓치거나 매번 프롬프트에 길게 써야 해요. 스킬이 있으면 키워드가 나올 때 자동으로 불려 와서 일관성이 생겨요. 사이트는 공개라 스킬에 비밀은 넣지 않아요.
토큰
새 프로젝트에 그대로 붙여 넣을 정의예요. 값은 Primitive와 같습니다.
Tailwind 설정
CSS 변수
Tailwind를 쓰지 않는 페이지(정적 HTML, 이메일 템플릿)에서는 이 변수만 복사해 쓰세요.
어디에 있나
| 항목 | 위치 |
|---|---|
| 토큰 원본 | rebound-biz / tailwind.config.js |
| 컴포넌트 클래스 | rebound-biz / src/index.css → @layer components |
| 화면 카탈로그 | rebound-biz / design. 전체 라우트와 모달을 시나리오별로 확인 |
| 아이콘 | lucide-react |
| 폰트 | Pretendard v1.3.9 (jsdelivr static) |