Groo Design

Tabs

다른 구역으로 옮기는 탭. 화면 · 구역 맨 위의 1차 탭은 Line(밑줄 막대), 그 안의 2차 탭은 Chip Tabs(칩 모양)다. 같은 내용을 2 ~ 4가지로 바로 거르거나 · 정렬하거나 · 다르게 보는 자리는 Segmented Control, 폼 값은 Select 의 "고르는 컴포넌트 고르기"(판단 순서), 목록 조건을 걸고 푸는 자리는 Chip 의 필터 바다. 화면 사이를 오가는 부품(하단 탭 바 · 사이드바 · 상단 바)과 고르는 표는 DESIGN.md Layout 의 "이동 부품 고르기" 한 곳이다.

구조는 당근 SEED Tabs(Apache-2.0)를 따른다 — Line 타입(목록 · 탭 · 글 · 막대)과 Chip 타입(칩 모양 탭), 1차 Line · 2차 Chip. 값은 groo 토큰이고, SEED 와 다른 자리는 맨 아래 "SEED 와 다른 점" 에 적었다(2026-10-02 사용자 결정).

수치 원본은 tabs.yaml(Line)과 chip-tabs.yaml(Chip Tabs — 칩 하나는 chip.yaml 그대로)이다. 수치 표 자리([표: …])와 그림 자리([그림: …])는 사이트가 그 파일로 그린다 — GitHub 에서는 그 파일 · 그림 코드로 가는 링크로 보인다.

9:41
증권
나무증권토스증권
보유관심발견
삼삼성전자10주712,000원
SSK하이닉스3주621,000원
NNAVER2주412,000원
9:41
통계
카테고리추이비교
10월 지출412,300원
식식비44%182,400원
쇼쇼핑22%89,000원
카카페13%52,300원
교교통12%48,600원
문문화6%25,000원
hr.groo.app
휴가 신청
신청 내역승인 내역새 소식
연차2026. 10. 12. (월)1일승인 대기
반차(오전)2026. 9. 25. (목)0.5일승인
연차2026. 9. 8. (월) ~ 9. 9. (화)2일승인
증권 · 통계 · 휴가 — 라이트 · 다크

직접 골라 보기

모양(Line · Chip Tabs) · 폭 · 크기 · 탭 수 · 알림 점 · 막힌 탭을 고르면 스펙대로 그린 탭과 그 코드가 바뀐다. 실제로 누르고 화살표로 옮길 수 있다.

카테고리
모양
폭 layout
크기 size
탭 수
알림 점 notification
막힌 탭 disabled
모드
브랜드
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

<Tabs value={tab} onValueChange={setTab}>
  <TabsList aria-label="통계">
    <TabsTrigger value="category">카테고리</TabsTrigger>
    <TabsTrigger value="trend">추이</TabsTrigger>
    <TabsTrigger value="compare">비교</TabsTrigger>
  </TabsList>
  <TabsContent value="category">…</TabsContent>
  <TabsContent value="trend">…</TabsContent>
  <TabsContent value="compare">…</TabsContent>
</Tabs>

Anatomy

신청 내역승인 내역새 소식
ⓐ Listⓑ Tabⓒ Labelⓓ Indicatorⓔ Notification
2배로 그렸다 — Fill · small, 고른 탭 아래 막대, 둘째 탭에 알림 점
탭은 목록 · 탭 · 글 · 막대로, 새 소식이 있는 탭 하나에 알림 점을 단다
부위설명
ⓐ List목록 — 놓인 화면 · 구역 폭을 채우고, 바닥에 1px 구획 선을 긋는다. 바탕은 불투명하다.
ⓑ Tab탭 하나 — 누르는 자리. 고르든 안 고르든 바탕이 없다.
ⓒ Label글 — 이름만, 한 줄. 고르면 글자색만 짙어진다(굵기 그대로).
ⓓ Indicator막대 — 고른 탭 아래 2px. 다른 탭을 고르면 미끄러져 옮긴다.
ⓔ Notification알림 점 — 새 소식이 있는 탭 하나에만, 글 오른쪽 위.

부위

부위설명
list목록 — 탭을 담는 줄. 놓인 화면 · 구역 폭을 채우고 바닥에 구획 선
trigger탭 하나 — 누르는 자리
label글 — 이름만(개수를 붙이지 않는다). 줄바꿈 · 말줄임하지 않고 탭이 넓어진다
indicator막대 — 고른 탭 아래 2px. 다른 탭을 고르면 미끄러져 옮긴다
notification알림 점 — 새 소식이 있는 탭 하나에만, 글 오른쪽 위. 내용을 보면 사라진다
focusRing키보드 포커스 링(웹) — 탭 안쪽
content내용 칸(tabpanel) — 고른 탭의 내용. 바로 바뀌고 다른 탭의 상태(스크롤 · 입력)를 남긴다. 탭이 경로인 웹(가계부 묶음)은 경로마다 스크롤을 기억한다

Properties

Layout

탭이 5개 이하이고 글이 짧으면 Fill — 칸을 똑같이 나눠 목록을 꽉 채우고, 막대는 칸에서 좌우 16 씩 들인다. 6개 이상이거나 글이 길면 Hug — 탭이 글만큼 넓어지고(글 + 좌우 10), 목록 좌우 16 · 넘치면 가로로 스크롤한다. Hug 에서는 고른 탭이 늘 보이게, 화면 밖 탭을 고르면 16 여유를 두고 그쪽으로 스크롤한다. 데스크톱의 넓은 카드 · 페이지처럼 칸을 나누면 탭이 지나치게 넓어지는 자리는 개수가 적어도 Hug 로 둔다. 글은 줄바꿈 · 말줄임하지 않는다. Fill 에서 글이 칸을 넘으면(영어처럼 글이 길어지는 언어에서 자주 그렇다) Hug 로 바꾸지 않고 Fill 모양 그대로 목록만 가로로 스크롤한다(SEED tabs.css — 목록은 늘 overflow-x auto). 그때도 고른 탭은 Hug 처럼 가장자리와 16 을 두고 드러낸다(scroll-padding 16 — 목록 좌우 여백은 0 그대로). 대가 — 첫 탭이 화면 끝 0 에서 시작하고 막대가 칸에서 16 들어간 모양 그대로라 잘린 끝 탭의 "더 있다" 단서가 약하다. 개수 · 글 길이로 미리 알면 처음부터 Hug 로 둔다(2026-10-21 사용자 결정 — 03-G 결정 3 B — 추천 A "부품이 재서 Hug 로" 가 아니다). 탭 줄 높이 40 · 44 는 px 최소 높이라 글이 크면 그만큼만 늘어난다(결정 1 A).

카테고리추이비교
Fill — 5개 이하 · 짧은 글칸을 똑같이 나눠 꽉 채우고 막대는 칸에서 좌우 16 씩 들인다 — 360 화면 2 · 3 · 4 · 5개면 막대 148 · 88 · 58 · 40
전체홈자산가계부통계예산증권더치페이기타
Hug — 6개 이상 · 긴 글탭이 글만큼(글 + 좌우 10) · 목록 좌우 16 · 넘치면 가로 스크롤 — 고른 탭이 화면 밖이면 16 여유를 두고 그쪽으로
hr.groo.app
권한
역할사용자
관리자구성원 · 휴가 정책 · 권한을 관리해요.
팀장팀원의 휴가 신청을 승인해요.
구성원휴가를 신청하고 내역을 봐요.
데스크톱의 넓은 카드 · 페이지 — 2개여도 Hug칸을 나누면 탭이 지나치게 넓어지는 자리 · HR 권한(역할 · 사용자)
폭 — Fill(칸을 나눈다) · Hug(글만큼, 넘치면 스크롤)

폭

layoutlist 좌우 여백list 넘칠 때list 스크롤 여유trigger 남는 자리 채움막대 들임설명
fill (기본)0pxauto — 글이 칸을 넘으면 Fill 모양 그대로 목록만 가로 스크롤 — 스크롤바는 숨긴다(SEED, 2026-10-21 03-G 3B)spacing-x4 16px — 넘쳐 스크롤할 때 고른 탭이 화면 밖이면 16 여유를 두고 가까운 쪽으로 스크롤한다 — Hug 와 같다(웹 · 앱이 이미 이렇게 한다, 2026-10-22 I-04 검수). 넘치지 않으면 하는 일이 없다1 — 칸을 똑같이 나눈다 — 글이 칸보다 길면 그 탭만 넓어지고, 넘치면 Fill 모양 그대로 목록만 가로 스크롤(SEED, 2026-10-21 03-G 3B)spacing-x4 16px — 탭 폭에서 좌우 16 씩 들인다 — 막대 = 탭 폭 − 32. 360 폰 2 · 3 · 4 · 5개면 148 · 88 · 58 · 40칸을 똑같이 나눠 꽉 채운다 — 5개 이하 · 짧은 글
hugspacing-x4 16px — SEED 16 — 탭의 좌우 10 이 더해져 첫 글이 26 에서 시작한다auto — 넘치면 가로 스크롤 — 스크롤바는 숨긴다spacing-x4 16px — 고른 탭이 화면 밖이면 16 여유를 두고 가까운 쪽으로 스크롤한다0 — 글 + 좌우 100px — 탭 폭 그대로(좌우 10 포함) — 글보다 20 길다글만큼 — 6개 이상이거나 글이 길 때. 넘치면 가로 스크롤

Size

small 40 · 글 14 (기본) · medium 44 · 글 16. 탭의 위아래 · 좌우는 둘 다 10 이고, 글을 아래로 붙여(아래 10) 막대와 글 사이가 크기와 관계없이 같다. 글은 고르든 안 고르든 700 이다. 어느 크기를 쓸지는 화면의 다른 글과의 조합 · 주목도로 고른다(SEED).

small 40 (기본)기본 — 통계 · 금액 가리기글 14 / 19 · 700위 11 · 아래 10 · 좌우 10
카테고리추이비교
medium 44주목도가 큰 1차 — 증권사 · 휴가 신청글 16 / 22 · 700위 12 · 아래 10 · 좌우 10
나무증권토스증권

분홍 띠 — 위아래 여백(글은 아래 10 에 붙고 남는 높이는 위로) · 점선 — 글 줄 · 글은 고르든 안 고르든 700

크기 — small 40 · medium 44

크기

sizelist 최소 높이trigger 최소 높이글자설명
small (기본)40px40pxtext-t4 14px / 19px — 14 / 19 — 글은 아래 10, 위 1140 · 글 14
medium44px44pxtext-t5 16px / 22px — 16 / 22 — 글은 아래 10, 위 1244 · 글 16

State

상태모습
enabled안 고른 글 fg-neutral-subtle, 고른 글 fg-neutral + 아래 막대
pressed탭을 2px 거리로 축소만 한다 — 색은 그대로다. 글자색이 이미 고름을 말하므로, 누르는 동안 색이 바뀌면 손을 떼기 전에 고른 것처럼 보인다(Foundation Feedback). 마우스 호버 모양도 없다. 고름은 손을 뗄 때(click) — 누른 채 밖으로 끌어내면 고르지 않는다. 키보드는 화살표로 바로 고른다(Behavior)
focused키보드 포커스에만 링 2px — 탭 안쪽(이웃 탭 · 바닥 선에 걸리지 않게)
disabled글 fg-disabled · 커서 not-allowed · 축소 없음. 화살표로 옮길 때 건너뛴다
안 고름고름기본
추이
추이
누름
추이
추이
포커스(키보드)
추이
추이
비활성
추이
추이
라이트누름은 탭 축소만(색 그대로) · 포커스 링은 탭 안쪽 · 막히면 글 fg-disabled, 고른 채 막히면 막대도 fg-disabled
안 고름고름기본
추이
추이
누름
추이
추이
포커스(키보드)
추이
추이
비활성
추이
추이
다크누름은 탭 축소만(색 그대로) · 포커스 링은 탭 안쪽 · 막히면 글 fg-disabled, 고른 채 막히면 막대도 fg-disabled
상태 — 기본 · 누름 · 포커스 · 비활성 × 안 고름 · 고름

상태 — 안 고름

상태trigger 배율trigger 커서trigger 축소 시간trigger 축소 곡선label 글자·아이콘링 두께링 간격링 색
enabled 기본 — 마우스 호버 모양은 없다(SEED)—pointer——color-fg-neutral-subtle #62697A · 다크 #A2A8B7———
pressed 탭을 2px 거리로 축소만 — 색은 그대로(이미 색이 고름을 말한다)탭 2px 거리 축소 — 기준 길이 max(높이, 폭 ÷ 4, 24) 에서 2px(SEED scaleScope: self · v104) — 모션 줄이기면 하지 않는다pointermotion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)color-fg-neutral-subtle #62697A · 다크 #A2A8B7———
focused 웹 — 키보드 포커스에만 링—pointer——color-fg-neutral-subtle #62697A · 다크 #A2A8B72px-2px — 탭 안쪽 — 이웃 탭 · 바닥 선에 걸리지 않는다. 모서리는 각지다(SEED)color-stroke-focus-ring #1A1F2E · 다크 #F5F6FA
disabled 막힌 탭 — 누를 수 없고 키보드 이동에서 건너뛴다—not-allowed — 축소 없음——color-fg-disabled #8A91A0 · 다크 #838997———

상태 — 고름

상태trigger 배율trigger 커서trigger 축소 시간trigger 축소 곡선label 글자·아이콘indicator 배경링 두께링 간격링 색
enabled 기본 — 마우스 호버 모양은 없다(SEED)—pointer——color-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색만 바뀐다 — 굵기 · 크기 그대로color-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색과 같은 짙은 중립색 — 브랜드 색이 아니다———
pressed 탭을 2px 거리로 축소만 — 색은 그대로(이미 색이 고름을 말한다)탭 2px 거리 축소 — 기준 길이 max(높이, 폭 ÷ 4, 24) 에서 2px(SEED scaleScope: self · v104) — 모션 줄이기면 하지 않는다pointermotion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)color-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색만 바뀐다 — 굵기 · 크기 그대로color-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색과 같은 짙은 중립색 — 브랜드 색이 아니다———
focused 웹 — 키보드 포커스에만 링—pointer——color-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색만 바뀐다 — 굵기 · 크기 그대로color-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색과 같은 짙은 중립색 — 브랜드 색이 아니다2px-2px — 탭 안쪽 — 이웃 탭 · 바닥 선에 걸리지 않는다. 모서리는 각지다(SEED)color-stroke-focus-ring #1A1F2E · 다크 #F5F6FA
disabled 막힌 탭 — 누를 수 없고 키보드 이동에서 건너뛴다—not-allowed — 축소 없음——color-fg-disabled #8A91A0 · 다크 #838997color-fg-disabled #8A91A0 · 다크 #838997 — 목록 전체가 막혔을 때 고른 탭의 막대도 전용 색———

모션

전환시간곡선대상비고
막대 — 미끄러짐motion-duration-d4 200msmotion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)left, width글자색은 전환 없이 바로 — 내용 칸도 애니메이션 없이 바로 바뀐다(폰 1차 탭의 밀어 넘기기는 손을 따라 움직인다)
누름 — 탭motion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)scale탭 2px 거리 축소 — 모션 줄이기면 하지 않는다

Chip Tabs

1차 Line 탭 안의 2차 탭이다. 칩 하나는 Chip 그대로 — solid 는 Chip Solid, outline 은 Chip Outline Strong, 크기는 Chip medium 36 (기본) · large 40 이다. 고르면 짙은 채움(bg-neutral-inverted · fg-neutral-inverted)이고, 누름 · 호버 · 포커스 · 비활성도 Chip 과 같다. 목록은 바탕 · 바닥 선 없이 한 줄 가로 스크롤이고, 칩 사이 8 · 좌우 화면 여백 24(Chip 의 가로 스크롤 줄과 같다) · 위아래 8 이다. 목록의 양 끝은 Scroll Fog 로 늘 흐린다(좌우 20 — 여백 24 가 더 넓어 처음 · 끝 칩은 흐리지 않는다).

  • 화면 전체 내용을 바꾸면 Solid, 일부 내용만 바꾸면 Outline(SEED).
  • large 는 화면 전체를 바꾸는 탭, medium 은 좁은 자리 · 스크롤 중간의 서브 내용(SEED).
  • 알림 점은 글 뒤 6 에 둔다(칩 안이라 오른쪽 위가 아니다).
  • 칩 하나가 보이는 목록 폭(화면 여백 안)보다 길면 그 폭에서 멈추고 글 끝을 "…" 로 줄인다(큰 글자 · 긴 이름) — 알림 점은 남는다. 탭의 이름 · 보조 기술은 글 전체다. Chip 의 "줄보다 긴 칩" 규칙 그대로다(2026-10-17 사용자 결정 — 03-E 후속). Line 탭의 글은 지금처럼 줄바꿈 · 말줄임하지 않는다(Fill 에서 넘치면 Hug).
Solidmedium 36 · 기본
보유관심발견
Solidlarge 40
보유관심발견
Outlinemedium 36
보유관심발견
Outlinelarge 40
보유관심발견
라이트고르면 짙은 채움 — Outline 은 고르면 테두리를 지운다
Solidmedium 36 · 기본
보유관심발견
Solidlarge 40
보유관심발견
Outlinemedium 36
보유관심발견
Outlinelarge 40
보유관심발견
다크고르면 짙은 채움 — Outline 은 고르면 테두리를 지운다
나무증권토스증권
보유관심새 소식발견
삼삼성전자10주712,000원
SSK하이닉스3주621,000원
1차 Line 아래 2차 Chip Tabs목록 좌우 24(화면 여백) · 위아래 8 · 칩 사이 8 · 바탕 · 바닥 선 없음 · 고른 칩이 화면 밖이면 24 여유를 두고 스크롤 · 알림 점은 글 뒤 6(칩이 그만큼 넓어진다, 고른 칩에는 없다) · 1차 막대는 Fill 이라 칸에서 16 들인다
Chip Tabs — Solid · Outline × medium · large

Chip Tabs — 변형

variant칩설명
solid (기본)Chip Solid — chip.yaml variant=solid — 안 고름 bg-neutral-weak, 고름 짙은 채움화면 전체 내용을 바꾸는 2차 탭 — Chip Solid(투명 바탕 — 회색 바닥 · 흰 표면 어디서나, v120)
outlineChip Outline Strong — chip.yaml variant=outlineStrong — 안 고름 투명 + 1px, 고름 짙은 채움(테두리 지움)일부 내용을 바꾸는 2차 탭 — Chip Outline Strong

Chip Tabs — 크기

size칩 크기설명
medium (기본)Chip medium — chip.yaml size=medium — 높이 · 좌우 · 글 · 최소 폭은 그 파일이 원본(36 · 14 · t4 500 · 48)36 — 기본. 좁은 자리 · 스크롤 중간의 서브 내용
largeChip large — chip.yaml size=large — 높이 · 좌우 · 글 · 최소 폭은 그 파일이 원본(40 · 16 · t4 500 · 52)40 — 화면 전체 내용을 바꾸는 탭

Chip Tabs — 목록 · 알림 점

부위속성값비고
list좌우 여백spacing-global-gutter 24px화면 여백 — Chip 의 가로 스크롤 줄과 같다(SEED 16)
list상하 여백spacing-x2 8px1차 Line 목록 아래 · 내용 위 8(SEED 에 없다 — 비교 페이지 그림의 값)
list간격spacing-between-chips 8px
list넘칠 때auto넘치면 가로 스크롤 — 스크롤바는 숨긴다
list끝 흐림좌우 20pxScroll Fog row(scroll-fog.yaml) — gradient-fade-mask 마스크, 늘 켜짐. 목록 좌우 여백 24 가 흐림보다 넓어 처음 · 끝의 칩은 흐리지 않는다(2026-10-03)
list스크롤 여유spacing-global-gutter 24px고른 칩이 화면 밖이면 화면 여백 24 를 두고 가까운 쪽으로 스크롤한다 — 첫 칩이 늘 화면 여백에서 선다(Chip 의 가로 스크롤 줄과 같다)
trigger줄어듦0줄어들지 않는다 — 글이 여백을 침범하지 않게(SEED)
notification크기6px
notification모서리radius-full 9999px
notification배경color-fg-brand HR #075B3C · Desk #0147AD브랜드 글자색 — 안 고른 칩(bg-neutral-weak · 투명) 위 Desk 7.76 · 4.69 · HR 7.56 · 4.67. 고른 칩(짙은 채움)에는 없다 — 내용을 보면 사라진다
notification간격spacing-x1_5 6px글 뒤 6, 세로 가운데 — 칩 폭이 그만큼 넓어진다(SEED)

Guidelines

탭은 다른 구역으로 옮길 때

탭은 탐색이다 — 누르면 탭 아래 내용 전체가 다른 구역으로 바뀐다. 화면 · 구역의 맨 위에 둔다. 같은 내용을 거르거나 · 정렬하거나 · 다르게 보는 조작은 그 내용 바로 위의 Segmented Control 이다. 화살표로 옮기기만 해도 고르므로(아래 Behavior), 바로 저장되거나 되돌리기 어려운 값은 탭에 두지 않는다.

이런 자리컴포넌트
다른 구역 · 페이지로 옮긴다(1차)Tabs — Line
1차 탭 안에서 다시 나눈다(2차)Tabs — Chip Tabs
같은 내용 2 ~ 4가지 거르기 · 정렬 · 보기Segmented Control
2 ~ 4개 짧은 폼 값 · 거르기의 한 축Chip(하나 고르기)
목록 조건을 여럿 걸고 푼다Chip(필터 바)
5개 이상 · 글이 긴 폼 값Select · Radio · Checkbox
켜고 끄는 단추 하나Toggle — 아이콘 단추
9:41
통계
카테고리추이비교
10월 지출412,300원
식식비44%182,400원
쇼쇼핑22%89,000원
카카페13%52,300원
교교통12%48,600원
이렇게 — 다른 구역으로 옮긴다 — 화면 맨 위 Line 탭, 누르면 아래 내용 전체가 바뀐다
9:41
가계부
전체지출수입
점점심 식사식비, 현대카드 M−12,000원
급급여수입, 국민은행+3,200,000원
스스타벅스카페, 현대카드 M−5,600원
지지하철교통, 국민 체크카드−1,450원
이렇게 — 같은 내용을 거른다 — 그 목록 바로 위 Segmented Control
9:41
거래 추가
지출수입이체
12,000원
점심 식사
이렇게 — 저장할 폼 값은 Chip(하나 고르기) · Select
9:41
거래 추가
지출수입이체
12,000원
점심 식사
이렇게 하지 않는다 — 폼 값을 탭으로 — 화살표로 옮기기만 해도 골라져 값이 바뀐다
쓰임 — 구역 이동은 탭 · 같은 내용 조작은 Segmented · 폼 값을 탭으로

탭 바보다 더 나눌 때 — 화면 위 Line

폰의 Bottom Navigation 은 다섯 칸이 어느 화면에서나 같다 — 더 나눌 구분은 탭 바 칸을 바꾸지 않고 그 탭 화면의 맨 위 1차 Line 으로 둔다(SEED Bottom Navigation — "더 많은 구분이 필요하다면 화면 상단에 Tabs 를 사용"). 화면 맨 위 1차 Line 은 어디서나 Top Navigation 바로 아래에 붙어 함께 고정된다(SEED Tabs stickyList). 숨는 것은 그 아래 스크롤 상자의 Scroll Auto Hide 뿐이다 — 화면을 오가는 1차 탭은 상단 바와 함께 남는다(Scroll Auto Hide 의 "숨지 않는 것").

Desk 에서는

아래는 부품 규칙이 아니라 Desk 의 화면 배치다(2026-10-22 사용자 결정 9B — https://claude.ai/artifact/Mag1tEv51MdQHdy1o8hY3L). Desk 의 가계부 탭은 화면 위 Line 넷(가계부 · 자산 · 통계 · 예산 — Fill · medium 44)이다. 머리 제목은 넷 모두 "가계부" 다(탭 바 칸의 이름 — 고른 탭은 Line 이 말한다. 문서 제목만 "{탭 이름} - 그루 담다"). 화면 위 Line 은 가계부 묶음 · 카테고리의 지출 · 수입에 둔다. 데스크톱(768 이상)에서는 넷이 Side Navigation 의 항목이라 이 탭 줄이 없다.

웹과 앱은 짜임이 다르고 겪는 것은 같다(2026-10-16 구현 세션 질문 Q-017-1 정리 — Tabs 7A · 화면 틀 7A).

  • 웹 — 넷은 각자의 경로다(/desk/expense · /desk/asset · /desk/stats · /desk/budget — 사이드바 항목도 같은 경로라 ?tab= 을 두지 않는다). 탭을 고르면 그 경로로 지금 주소를 고쳐 쓰고(replace — 뒤로 가기가 탭을 되짚지 않는다), 다른 탭을 다녀오면 그 탭의 스크롤로 돌아온다(경로마다 기억 — 목록이 그려진 뒤 돌려놓는다, 못 하면 맨 위). 기억 · 복원은 화면의 몫이다.
  • 앱 — 넷은 한 화면 안 Tabs 다(TabsSwipeArea) — 탭마다 상태(스크롤 · 필터)가 남고 옆으로 밀어 넘긴다. 경로 넷(/expense?… 등)은 그 탭을 여는 입구로 그대로 받는다. 뒤로 버튼 동작은 그 한 화면에 한 번이다.

고쳐 쓰기(replace)는 Tabs 스펙 문장(2026-10-02)이고 7A 원문은 "웹은 주소에" 다.

그 안에서 다시 나누는 탭(통계의 카테고리 · 추이 · 비교)은 폰에서 2차가 되어 아래 "두 단" 규칙(2026-10-02)을 따른다 — 2차는 Chip Tabs 이고, 통계 화면에 필터 칩이 함께 있으면 Line 이다. 데스크톱에서는 1차 Line 그대로다. 앱 통계 안의 2차 밀어 넘기기는 걷는다 — 옆으로 밀면 1차(예산)로 넘어가고, 2차는 눌러서만 바꾼다(아래 "내용 바꾸기").

9:41
가계부
가계부자산통계예산
10월 2일 (금)−19,050원
점점심 식사식비, 현대카드 M−12,000원
지지하철교통, 국민 체크카드−1,450원
월월급수입, 국민 주계좌+3,200,000원
편편의점식비, 현금−4,300원
영영화문화, 국민 체크카드−15,000원
스스타벅스카페, 현대카드 M−5,600원
택택시교통, 현대카드 M−9,800원
이렇게 — 가계부 — 상단 바 바로 아래 Line 넷(가계부 · 자산 · 통계 · 예산), 탭 바는 홈 · 가계부 · + · 캘린더 · 전체 그대로
9:41
가계부
가계부자산통계예산
계좌
국국민 주계좌입출금2,450,000원
저저축 통장저축1,200,000원
나나무증권투자8,830,000원
현현대카드 M이번 달 사용−412,300원
이렇게 — 자산을 골라도 탭 바는 바뀌지 않는다 — 지금 탭은 가계부, 캘린더 · 전체로 한 번에 간다
폰 가계부 — 상단 바 아래 Line 넷 · 탭 바는 그대로

두 단 — 1차 Line · 2차 Chip Tabs

탭 안에서 다시 나누면 1차는 Line, 2차는 Chip Tabs 로 둔다 — 두 단이 같은 모양이면 어느 줄이 큰 갈래인지 보이지 않는다. 화면에 필터 바(거르는 칩)가 함께 있으면 2차도 Line 으로 둔다 — Chip Tabs 와 필터 칩이 같은 모양이면 무엇이 탭인지 알 수 없다.

9:41
증권
나무증권토스증권
보유관심발견
삼삼성전자10주712,000원
SSK하이닉스3주621,000원
NNAVER2주412,000원
이렇게 — 1차 Line(증권사) · 2차 Chip Tabs(보기) — 모양이 달라 큰 갈래가 보인다
9:41
증권
나무증권토스증권
보유관심발견
국내급상승
셀셀트리온많이 찾는 종목182,400원
LLG에너지솔루션많이 찾는 종목368,000원
이렇게 하지 않는다 — Chip Tabs 아래 필터 바 — 칩이 같은 모양이라 무엇이 탭인지 알 수 없다. 필터 바가 있으면 2차도 Line 으로
두 단 — 1차 Line · 2차 Chip Tabs · 필터 바와 겹친 Chip Tabs

폭 — 5개까지 Fill, 6개부터 Hug

짧은 2 ~ 5개는 Fill 로 칸을 나누고, 6개 이상이거나 글이 길어 칸을 넘으면 Hug 로 둔다. Fill 을 억지로 좁혀 글을 자르거나 줄이지 않는다.

9:41
금액 가리기
전체홈자산가계부통계예산증권더치페이기타
전체
이렇게 — 6개 이상은 Hug — 탭이 글만큼 넓고, 넘치면 가로로 스크롤한다
9:41
금액 가리기
전체홈자산가계부더치페이기타
전체
이렇게 하지 않는다 — Fill 에 6개를 욱여넣기 — 칸이 글보다 좁아 글이 잘린다
폭 — 6개는 Hug · Fill 에 6개를 욱여넣기

글 — 이름만, 알림 점은 하나

탭 글은 이름만 쓴다 — "진행 중 3" 처럼 개수를 붙이지 않는다. 수가 바뀔 때마다 탭 폭이 흔들리고, 탭이 "얼마나 있나" 를 알리는 자리가 된다. 개수가 필요하면 내용 안에서 보인다. 새 소식은 그 탭 하나에만 알림 점(6)을 달고, 내용을 보면 지운다 — 여러 탭에 동시에 달지 않는다. 글은 명사로 짧게, 한 묶음의 말투를 맞춘다.

9:41
카테고리
지출수입
식식비점심, 저녁, 장보기
카카페커피, 디저트
교교통버스, 지하철, 택시
이렇게 — 이름만 — 개수가 필요하면 내용 안에서 보인다
9:41
카테고리
지출 23수입 9
식식비점심, 저녁, 장보기
카카페커피, 디저트
교교통버스, 지하철, 택시
이렇게 하지 않는다 — 글에 개수 — "지출 23" 처럼 수가 바뀔 때마다 탭 폭이 흔들린다
9:41
증권
나무증권토스증권
보유관심새 소식발견
삼삼성전자10주712,000원
SSK하이닉스3주621,000원
NNAVER2주412,000원
이렇게 — 새 소식은 그 탭 하나에 알림 점 — 내용을 보면 지운다(고른 탭에는 없다)
9:41
증권
나무증권토스증권
보유관심새 소식발견새 소식
삼삼성전자10주712,000원
SSK하이닉스3주621,000원
NNAVER2주412,000원
이렇게 하지 않는다 — 여러 탭에 알림 점 — 새 소식은 한 탭에만 단다
글 — 이름만 · 알림 점 하나 · 글에 개수 · 여러 탭에 점

내용 바꾸기 — 바로, 상태를 남긴다

탭을 고르면 내용 칸이 애니메이션 없이 바로 바뀐다(막대만 200ms 로 미끄러진다). 탭마다 스크롤 · 입력 같은 상태를 남겨, 다른 탭을 다녀와도 그대로다 — 내용 칸 안의 입력 · 스크롤은 부품이 남기고, 페이지 전체가 스크롤되는 화면이면 화면이 탭마다 스크롤 위치를 기억했다가 돌려놓는다(웹 가계부 묶음처럼 탭이 경로이면 경로마다 — 목록이 그려진 뒤 돌려놓는다). 탭을 바꿔도 초점은 고른 탭에 남는다. 폰에서 화면 전체를 바꾸는 1차 탭만 내용을 옆으로 밀어 넘길 수 있다(가로로 스크롤하는 영역 위에서는 넘기지 않는다). 웹은 1차 탭을 주소에 남긴다 — 뒤로 가기 · 링크 · 새로고침이 같은 탭으로 돌아온다. 탭을 바꿀 때는 지금 주소를 고쳐 쓴다(방문 기록을 쌓지 않는다) — 뒤로 가기가 탭을 하나씩 되짚지 않고 이전 화면으로 간다.

9:41
통계
카테고리추이비교
10월 지출412,300원
식식비182,400원
쇼쇼핑89,000원
카카페52,300원
달마다 지출
폰 — 1차 탭만 밀어 넘긴다내용이 손을 따라 움직이고, 놓으면 이웃 탭으로 넘어간다 · 2차 탭 · Segmented · 가로로 스크롤하는 영역 위에서는 넘기지 않는다
desk.groo.app/stats?tab=trend
desk.groo.app/stats?tab=trend
통계
카테고리추이비교
달마다 지출
5월
6월
7월
8월
9월
10월
웹 — 1차 탭을 주소에?tab=trend — 뒤로 가기 · 링크 · 새로고침이 같은 탭(추이)을 연다. 탭마다 스크롤 · 입력은 남는다
내용 — 폰 1차 탭 밀어 넘기기 · 웹 주소의 탭

코드

레시피 recipes/shadcn/components/ui/tabs.tsx 를 쓴다(Radix Tabs 위 — 화살표로 옮기면 바로 고른다). 목록에 보이는 제목이 없으면 aria-label 로 이름을 단다. 아래 미리보기는 스펙 값으로 그린 모습이다.

Line — Fill

통계
10월 지출
412,300원
  • 식비44%182,400원
  • 쇼핑22%89,000원
  • 카페13%52,300원
  • 교통12%48,600원
  • 문화6%25,000원
  • 의료4%15,000원
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

<Tabs value={tab} onValueChange={setTab}>
  <TabsList aria-label="통계">
    <TabsTrigger value="category">카테고리</TabsTrigger>
    <TabsTrigger value="trend">추이</TabsTrigger>
    <TabsTrigger value="compare">비교</TabsTrigger>
  </TabsList>
  <TabsContent value="category">…</TabsContent>
  <TabsContent value="trend">…</TabsContent>
  <TabsContent value="compare">…</TabsContent>
</Tabs>

Line — Hug · 알림 점

금액 가리기
전체
휴가 신청
  • 연차2026. 10. 12. (월)1일승인 대기
  • 반차(오전)2026. 9. 25. (목)0.5일승인
  • 연차2026. 9. 8. (월) ~ 9. 9. (화)2일승인
{/* value 는 글이 아니라 바뀌지 않는 id — 글에 빈칸이 있으면 탭 · 내용 칸의 id 연결이 깨진다 */}
<Tabs value={screen} onValueChange={setScreen}>
  <TabsList layout="hug" aria-label="금액 가리기">
    {SCREENS.map((s) => (
      <TabsTrigger key={s.id} value={s.id}>{s.label}</TabsTrigger>
    ))}
  </TabsList>
  …
</Tabs>

<Tabs value={tab} onValueChange={setTab}>
  <TabsList layout="hug" size="medium" aria-label="휴가 신청">
    <TabsTrigger value="mine">신청 내역</TabsTrigger>
    <TabsTrigger value="approval" notification={hasPending}>승인 내역</TabsTrigger>
  </TabsList>
  …
</Tabs>

두 단 — Chip Tabs

증권
  • 삼성전자10주712,000원
  • SK하이닉스3주621,000원
  • NAVER2주412,000원
import { ChipTabsList, ChipTabsTrigger, Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

<Tabs value={broker} onValueChange={setBroker}>
  <TabsList size="medium" aria-label="증권사">
    <TabsTrigger value="namu">나무증권</TabsTrigger>
    <TabsTrigger value="toss">토스증권</TabsTrigger>
  </TabsList>
  <TabsContent value="namu">
    <Tabs value={view} onValueChange={setView}>
      <ChipTabsList variant="solid" aria-label="나무증권 보기">
        <ChipTabsTrigger value="holding">보유</ChipTabsTrigger>
        <ChipTabsTrigger value="watch">관심</ChipTabsTrigger>
        <ChipTabsTrigger value="discover">발견</ChipTabsTrigger>
      </ChipTabsList>
      <TabsContent value="holding">…</TabsContent>
      …
    </Tabs>
  </TabsContent>
  …
</Tabs>

밀어 넘기기 · 주소 — 폰 · 웹의 1차 탭

폰에서 화면 전체를 바꾸는 1차 탭만 내용 칸을 TabsSwipeArea 로 감싼다(2차 탭 · Segmented Control 에는 두지 않는다). 웹은 값을 주소에 두고, 탭을 바꿀 때 지금 주소를 고쳐 쓴다(replace).

import { useSearchParams } from "react-router-dom"
import { Tabs, TabsContent, TabsList, TabsSwipeArea, TabsTrigger } from "@/components/ui/tabs"

const [params, setParams] = useSearchParams()
const tab = params.get("tab") ?? "category"

<Tabs value={tab} onValueChange={(v) => setParams((p) => { p.set("tab", v); return p }, { replace: true })}>
  <TabsList aria-label="통계">
    <TabsTrigger value="category">카테고리</TabsTrigger>
    <TabsTrigger value="trend">추이</TabsTrigger>
    <TabsTrigger value="compare">비교</TabsTrigger>
  </TabsList>
  <TabsSwipeArea>
    <TabsContent value="category">…</TabsContent>
    <TabsContent value="trend">…</TabsContent>
    <TabsContent value="compare">…</TabsContent>
  </TabsSwipeArea>
</Tabs>

Behavior

인터랙션동작
Click · Tap손을 뗄 때 그 탭을 고르고 내용 칸을 바로 바꾼다 — 누르는 동안은 축소만 하고, 누른 채 밖으로 끌어내면 고르지 않는다(2026-10-15 구현 세션 질문 Q-010-1 정리 — 사용자 결정 "누름은 축소만"). 막대가 200ms 로 미끄러진다. Chip Tabs 도 같다.
← →이웃 탭으로 옮기며 바로 고른다(자동). 끝에서 처음으로 돌고, 막힌 탭은 건너뛴다.
Home · End첫 · 마지막 탭(막히지 않은)으로 옮기며 고른다.
Tab목록에서는 고른 탭 하나에만 선다. 다음 Tab 은 내용 칸으로 간다.
폰 1차 탭 밀어 넘기기내용을 옆으로 밀면 이웃 탭으로 넘어간다 — 내용은 손을 따라 움직이고, 막대는 지금 탭에 있다가 손을 떼고 넘어가면 200ms 로 옮긴다. 칸 폭의 25% 를 넘기거나 빠르게 튕기면 넘어가고, 아니면 제자리로. 2차 탭 · Segmented 에는 없다.
화면 밖 탭을 고름(Hug · Chip Tabs)그 탭이 보이게 목록만 스크롤한다 — Hug 는 16, Chip Tabs 는 화면 여백 24 를 남긴다.
다른 탭을 다녀옴탭마다 스크롤 · 입력 상태가 남아 있다.
웹 1차 탭주소에 남는다(지금 주소를 고쳐 쓰고 기록을 쌓지 않는다) — 뒤로 가기 · 링크 · 새로고침이 같은 탭을 연다.
Disabled누를 수 없다 · 커서 not-allowed · 화살표 이동에서 건너뛴다.

Accessibility

기준검증
WCAG 1.4.3 Color contrast(글자 ≥ 4.5:1)안 고른 글 fg-neutral-subtle 목록 위 5.50 · 6.09, 고른 글 fg-neutral 16.41 · 13.42 ✓. 비활성 fg-disabled 는 기준 밖(비활성 UI). Chip Tabs 는 Chip 의 검증 그대로
WCAG 1.4.11 Non-text contrast(≥ 3:1)고름은 막대 2px fg-neutral(목록 바탕과 16.41 · 13.42)로 알린다 ✓. 바닥 구획 선(1.15 · 1.30)은 목록을 알리는 유일한 표시가 아니다. 키보드 포커스 링 Desk 8.38 · 6.10 · HR 8.17 · 6.07 ✓. 알림 점 fg-brand 목록 바탕과 Desk 8.38 · 6.10 · HR 8.17 · 6.07, 칩 바탕(bg-neutral-weak)과 7.76 · 4.69 · 7.56 · 4.67 ✓ — 고른 탭에는 그리지 않는다
WCAG 1.4.1 Use of color고름은 글자색만이 아니라 막대로도 알린다 ✓
WCAG 2.4.7 Focus visible키보드 포커스에 링 2px — 탭 안쪽
WCAG 2.5.8 Target Size — Minimum(AA ≥ 24×24)small 40 · medium 44 ✓(가로는 탭 폭 — Hug 도 글 + 20)
WCAG 2.5.5 Target Size — Enhanced(AAA ≥ 44×44)medium 44 ✓ · small 40 ✗(40 — 목록 높이가 곧 누르는 높이다. SEED 와 같다)
앱(Flutter 3.44.9)Flutter 는 tab · tabBar 역할을 Android · iOS 화면 읽기에 전달하지 않는다. 그래서 앱 탭은 이름 끝에 "탭 n/m"(영어 "Tab n of m")을 붙이고 선택됨 상태를 둔다 — Flutter Material TabBar 와 같은 풀이다. 버튼 역할은 두지 않는다(탭을 버튼으로 읽히게 하지 않는다). Line 탭 · Chip Tabs 가 같다(2026-10-22 I-04 검수 — 디자인 세션 판단)
ARIA목록 role="tablist"(이름은 보이는 제목 또는 aria-label), 탭 role="tab" + aria-selected · aria-controls, 내용 칸 role="tabpanel" + aria-labelledby(포커스할 것이 없는 칸은 tabindex="0"). 고른 탭만 tabindex="0"(로빙). 막힌 탭 disabled. 알림 점은 보조 기술에 "새 소식" 을 덧붙인다(점만으로 알리지 않는다)

Do / Don't

✅ Do

  • 다른 구역으로 옮기는 자리에 탭을 쓰고, 화면 · 구역 맨 위에 둔다.
  • 두 단이면 1차 Line · 2차 Chip Tabs.
  • 5개까지 Fill, 6개부터 · 긴 글은 Hug.
  • 글은 이름만, 새 소식은 한 탭에 알림 점 하나.
  • 고른 표시는 중립색 막대 — Desk · HR 이 같다.

❌ Don't

  • 폼 값 · 바로 저장되는 설정을 탭으로(Chip · Select).
  • 같은 내용을 거르는 2 ~ 4개를 탭으로(Segmented Control).
  • 고른 탭을 브랜드 색 · 굵기로 바꾸기.
  • 탭 글에 개수 붙이기 · 여러 탭에 알림 점.
  • Chip Tabs 와 필터 칩을 한 화면에 같은 모양으로.

Specification

tabs.yaml · chip-tabs.yaml 의 규칙을 하나도 빼지 않고 조건마다 그린다 — 웹 · 앱이 Tabs 를 만들 때 이 값을 그대로 쓴다. 조건이 없는 Base 가 모든 조합에 걸리고, 뒤의 규칙이 앞의 같은 값을 덮는다. 상태는 enabled 에서 바뀌는 값만 적었다. Chip Tabs 의 칩 하나는 Chip 의 Specification 이다.

Base

부위상태속성값
listenabled배경backgroundbg-layer-default#FFFFFF다크 #242938불투명 — 위에 붙어 있어도 아래 내용이 비치지 않는다
아래 테두리borderBottomColorstroke-neutral-subtle#EDEFF3다크 #353B4D안쪽 1px(inset) — 선이 탭 높이를 밀지 않는다. SEED stroke.neutral-muted 의 불투명 구획 선(v102)
아래 테두리 두께borderBottomWidth1px
자리position화면 맨 위 1차 — 상단 바 아래 고정화면 맨 위 1차 Line 은 어디서나 Top Navigation 바로 아래에 붙어 함께 고정된다(SEED Tabs stickyList — Desk 가계부 묶음 · 카테고리 지출 · 수입). 숨지 않는다 — 숨는 것은 그 아래 스크롤 상자의 Scroll Auto Hide 뿐(2026-10-16 구현 세션 질문 Q-017-5 정리)
triggerenabled상하 여백paddingYspacing-x2_510px
좌우 여백paddingXspacing-x2_510px
세로 맞춤alignItemsflex-end글을 아래로 붙인다 — 아래 10, 남는 높이는 위로(SEED)
커서cursorpointer
터치 영역touchTarget탭 전체목록 높이가 곧 누르는 높이 — small 40 · medium 44. 가로는 탭 폭(Hug 는 글 + 20)
labelenabled글자·아이콘foregroundfg-neutral-subtle#62697A다크 #A2A8B7
굵기fontWeight700고르든 안 고르든 700 — 고를 때 폭이 흔들리지 않는다
indicatorenabled높이height2px
모서리radius0px끝이 각지다(SEED)
배경backgroundfg-neutral#1A1F2E다크 #F5F6FA글자색과 같은 짙은 중립색 — 브랜드 색이 아니다
전환 대상transitionPropertyleft, width고른 탭의 자리 · 폭으로 미끄러진다. 글자색은 전환 없이 바로 바뀐다
전환 시간transitionDurationmotion-duration-d4200ms
전환 곡선transitionEasingmotion-ease-easingcubic-bezier(0.35, 0, 0.35, 1)
notificationenabled크기size6px
간격gap2px글 끝에서 2, 글 위쪽에 맞춘다 — 탭 폭을 넓히지 않는다
모서리radiusradius-full9999px(알약)
배경backgroundfg-brandDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84브랜드 글자색 — 목록 바탕과 Desk 8.38 · 6.10 · HR 8.17 · 6.07(bg-brand-solid 는 다크에서 Desk · HR 1.73 이라 안 보인다). 고른 탭에는 없다 — 내용을 보면 사라진다
triggerpressed배율scale탭 2px 거리 축소기준 길이 max(높이, 폭 ÷ 4, 24) 에서 2px(SEED scaleScope: self · v104) — 모션 줄이기면 하지 않는다
축소 시간scaleDurationmotion-duration-pressed-scale150ms
축소 곡선scaleEasingmotion-ease-pressed-scalecubic-bezier(0, 0, 0.15, 1)
focusRingfocused링 두께width2px
링 색colorstroke-focus-ringDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84
링 간격offset-2px탭 안쪽 — 이웃 탭 · 바닥 선에 걸리지 않는다. 모서리는 각지다(SEED)
triggerdisabled커서cursornot-allowed축소 없음
labeldisabled글자·아이콘foregroundfg-disabled#8A91A0다크 #838997

selected=selected

부위상태속성값
labelenabled글자·아이콘foregroundfg-neutral#1A1F2E다크 #F5F6FA글자색만 바뀐다 — 굵기 · 크기 그대로
indicatordisabled배경backgroundfg-disabled#8A91A0다크 #838997목록 전체가 막혔을 때 고른 탭의 막대도 전용 색

layout=fill

부위상태속성값
listenabled좌우 여백paddingX0px
넘칠 때overflowXauto글이 칸을 넘으면 Fill 모양 그대로 목록만 가로 스크롤 — 스크롤바는 숨긴다(SEED, 2026-10-21 03-G 3B)
스크롤 여유scrollPaddingspacing-x416px넘쳐 스크롤할 때 고른 탭이 화면 밖이면 16 여유를 두고 가까운 쪽으로 스크롤한다 — Hug 와 같다(웹 · 앱이 이미 이렇게 한다, 2026-10-22 I-04 검수). 넘치지 않으면 하는 일이 없다
triggerenabled남는 자리 채움grow1칸을 똑같이 나눈다 — 글이 칸보다 길면 그 탭만 넓어지고, 넘치면 Fill 모양 그대로 목록만 가로 스크롤(SEED, 2026-10-21 03-G 3B)
indicatorenabled막대 들임insetXspacing-x416px탭 폭에서 좌우 16 씩 들인다 — 막대 = 탭 폭 − 32. 360 폰 2 · 3 · 4 · 5개면 148 · 88 · 58 · 40

layout=hug

부위상태속성값
listenabled좌우 여백paddingXspacing-x416pxSEED 16 — 탭의 좌우 10 이 더해져 첫 글이 26 에서 시작한다
넘칠 때overflowXauto넘치면 가로 스크롤 — 스크롤바는 숨긴다
스크롤 여유scrollPaddingspacing-x416px고른 탭이 화면 밖이면 16 여유를 두고 가까운 쪽으로 스크롤한다
triggerenabled남는 자리 채움grow0글 + 좌우 10
indicatorenabled막대 들임insetX0px탭 폭 그대로(좌우 10 포함) — 글보다 20 길다

size=small

부위상태속성값
listenabled최소 높이minHeight40px
triggerenabled최소 높이minHeight40px
labelenabled글자typographytext-t414px / 19px14 / 19 — 글은 아래 10, 위 11

size=medium

부위상태속성값
listenabled최소 높이minHeight44px
triggerenabled최소 높이minHeight44px
labelenabled글자typographytext-t516px / 22px16 / 22 — 글은 아래 10, 위 12

Base

부위상태속성값
listenabled상하 여백paddingYspacing-x28px1차 Line 목록 아래 · 내용 위 8(SEED 에 없다 — 비교 페이지 그림의 값)
좌우 여백paddingXspacing-global-gutter24px화면 여백 — Chip 의 가로 스크롤 줄과 같다(SEED 16)
간격gapspacing-between-chips8px
넘칠 때overflowXauto넘치면 가로 스크롤 — 스크롤바는 숨긴다
스크롤 여유scrollPaddingspacing-global-gutter24px고른 칩이 화면 밖이면 화면 여백 24 를 두고 가까운 쪽으로 스크롤한다 — 첫 칩이 늘 화면 여백에서 선다(Chip 의 가로 스크롤 줄과 같다)
끝 흐림fog좌우 20pxScroll Fog row(scroll-fog.yaml) — gradient-fade-mask 마스크, 늘 켜짐. 목록 좌우 여백 24 가 흐림보다 넓어 처음 · 끝의 칩은 흐리지 않는다(2026-10-03)
triggerenabled줄어듦shrink0줄어들지 않는다 — 글이 여백을 침범하지 않게(SEED)
notificationenabled크기size6px
간격gapspacing-x1_56px글 뒤 6, 세로 가운데 — 칩 폭이 그만큼 넓어진다(SEED)
모서리radiusradius-full9999px(알약)
배경backgroundfg-brandDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84브랜드 글자색 — 안 고른 칩(bg-neutral-weak · 투명) 위 Desk 7.76 · 4.69 · HR 7.56 · 4.67. 고른 칩(짙은 채움)에는 없다 — 내용을 보면 사라진다

variant=solid

부위상태속성값
triggerenabled칩chipChip Solidchip.yaml variant=solid — 안 고름 bg-neutral-weak, 고름 짙은 채움

variant=outline

부위상태속성값
triggerenabled칩chipChip Outline Strongchip.yaml variant=outlineStrong — 안 고름 투명 + 1px, 고름 짙은 채움(테두리 지움)

size=medium

부위상태속성값
triggerenabled칩 크기chipSizeChip mediumchip.yaml size=medium — 높이 · 좌우 · 글 · 최소 폭은 그 파일이 원본(36 · 14 · t4 500 · 48)

size=large

부위상태속성값
triggerenabled칩 크기chipSizeChip largechip.yaml size=large — 높이 · 좌우 · 글 · 최소 폭은 그 파일이 원본(40 · 16 · t4 500 · 52)

SEED 와 다른 점

  • 목록 바닥 선을 불투명 구획 선으로(v102) — SEED stroke.neutral-muted(반투명) → stroke-neutral-subtle.
  • Line 의 막대 들임 · Hug 목록 좌우는 SEED 처럼 16 — groo 의 화면 여백 24(spacing-global-gutter)를 쓰지 않는다. 탭이 제 좌우 10 을 더해 Hug 의 첫 글이 26 에서 시작해 본문 글의 24 와 거의 맞는다.
  • Chip Tabs 목록 좌우는 화면 여백 24 — SEED 16. Chip 의 가로 스크롤 줄(필터 바 · 제안 줄)과 같게, 칩 줄은 어디서나 첫 칩이 화면 여백에서 시작한다. 위아래 8 은 SEED 에 없는 값이다.
  • Chip Tabs 의 칩은 groo Chip 그대로 — 비활성은 흐리게 하지 않고(v106), Outline 을 고르면 테두리를 지운다(SEED Chip Tabs 와 같다).
  • 알림 점은 브랜드 글자색(fg-brand — Desk · HR 이 다르다)이고, 보조 기술에 "새 소식" 을 덧붙인다(SEED 는 점만 그린다). SEED 의 bg.brand-solid 짝은 groo 다크에서 바탕과 Desk · HR 1.73:1 이라 점이 안 보인다. 고른 탭에는 점을 그리지 않는다(내용을 보면 사라진다).
  • 웹은 1차 탭을 주소에 남긴다 — SEED 에 없는 규칙이다(사용자 결정 2026-10-02). 내용은 SEED 기본처럼 바로 바꾸고 상태를 남긴다.

Migration notes

2026-10-22 — Desk 배치 소제목 · 이동 부품 표 링크

"탭 바보다 더 나눌 때" 에서 Desk 의 가계부 넷 · 머리 제목 · 데스크톱 사이드바 문단을 "Desk 에서는" 소제목 아래로 옮겼다 — 부품 규칙(화면 위 1차 Line · 상단 바 아래 고정)은 위에 남는다(9B). 머리말에 DESIGN.md Layout 의 "이동 부품 고르기" 링크(6B). 사용자 결정 — https://claude.ai/artifact/Mag1tEv51MdQHdy1o8hY3L. 문장 이동만, 값 변경 없음.

2026-10-22 — 넘친 Fill 의 가장자리 16 · 앱 탭 이름(I-04 검수)

  • 넘친 Fill 의 scroll-padding 16 — 웹 · 앱 모두 넘쳐 스크롤하는 Fill 목록에서 고른 탭을 가장자리와 16 을 두고 드러내는데, yaml 은 Hug 에만 scrollPadding 을 적었고 레시피 Fill 에는 없었다. yaml Fill 에 overflowX · scrollPadding x4 를, 레시피 Fill 에 scroll-px-x4 를 적어 맞췄다. 목록 좌우 여백은 0 그대로다.
  • 앱 탭 이름 — Flutter 3.44.9 가 tab · tabBar 역할을 Android · iOS 에 전달하지 않아, 앱은 이름 끝에 "탭 n/m" 을 붙이고 선택됨을 둔다(버튼 역할은 두지 않는다 — Accessibility 의 앱 줄).

2026-10-22 — 폼 값 고르기는 Select 의 판단 순서로

머리글의 "2 ~ 4개 짧은 폼 값은 Chip · 5개 이상은 Select" 사본을 Select 의 "고르는 컴포넌트 고르기" 링크로 바꿨다(사용자 결정 1B — https://claude.ai/artifact/SmHD31RQxTjWbfK83nbcym).

2026-10-21 — 넘치는 Fill · 단위(03-G)

결정 3 B — Fill 이 넘치면 Hug 로 바꾸지 않고 목록만 가로 스크롤한다(SEED, https://claude.ai/artifact/A3oCdxNvDwkNBPFPE36bmF). 스펙의 "Hug 로 바꾼다" 는 누가 바꾸는지 없었다(조사 03G-027 [스펙 모순]). 레시피 Fill 목록에 overflow-x-auto(스크롤바 숨김) · 고른 탭 드러내기를 Fill 에도 걸고, "Fill 목록이 넘친다" 개발 경고는 걷었다. 앱도 Fill 에 가로 스크롤. 거절: 부품이 재서 Hug 로 · 쓰는 쪽이 고름. 결정 1 A — 탭 줄 min-h-[40px] · [44px] · 알림 점 size-[6px](px).

2026-10-17 — Chip Tabs 의 긴 칩은 말줄임(03-E 후속)

Chip 의 "줄보다 긴 칩은 줄 폭에서 말줄임"(03-E 결정 2 A)이 가로 스크롤 줄 · Chip Tabs 에도 걸린다고 사용자가 확인했다 — 칩 하나의 최대 폭은 보이는 목록 폭(화면 여백 안)이다. chip.yaml 의 root.maxWidth 를 칩 하나가 그대로 따르므로 chip-tabs.yaml 은 바뀌지 않는다. 옛 스펙은 tabs.history/v-pre-03e-03b.md.

2026-10-16 — 가계부 묶음 · 화면 맨 위 Line(구현 세션 질문 Q-017-1 · Q-017-5 · Q-018-4 정리)

구현 질문 Q-017 · Q-018 비교 페이지의 정리 표를 사용자가 추천대로 정했다(2026-10-16). 이미 있는 결정(Tabs 7A — 상태를 남기고 폰 1차만 밀어 넘김 · 웹은 주소에, 화면 틀 7A — 탭 바 그대로 · 위 Tabs, Tabs 결정 8 — 글에 개수 없음)이 답한다.

  • 웹 — 경로 넷을 그대로 두고 탭을 고르면 navigate(path, { replace: true })(증권사 탭 StocksPage.tsx:75-87 과 같다), 탭(경로)마다 스크롤을 기억한다 — 지금 임시 MoneyTabs 는 탭을 바꾸면 focusScreenTitle 이 맨 위로 보낸다. 탭 줄은 medium 44(임시는 small 40). 머리 제목은 넷 모두 "가계부"(임시는 탭마다 바뀐다 — 자산 · 통계·분석 · 예산).
  • 앱 — 가계부 · 자산 · 통계 · 예산을 한 화면 + 안쪽 Tabs(TabsSwipeArea)로 묶는다 — 지금은 같은 branch 안 경로 넷을 context.go 로 바꿔 끼워 앞 탭의 스크롤 · 필터가 사라진다(mobile_scaffold.dart:75-77). 경로 넷(16곳)은 그 탭을 여는 입구로 받고, BranchBackToHome 은 그 한 화면에 한 번. 통계 안의 2차 밀어 넘기기(stats_screen.dart:416-417 PageView)는 걷는다.
  • 카테고리 화면(앱) — 지출 · 수입 Line 은 바 바로 아래 고정(AppBar bottom 그대로의 자리), 글의 개수("지출 12")를 뺀다(category_screen.dart:131-142).

2026-10-15 — 구현 세션 질문(Q-010-1 · Q-010-2 · Q-010-4)

  • 고름은 손을 뗄 때(Q-010-1, 정리) — 레시피가 Radix 기본(마우스를 누르는 순간 고름)이라 "누름은 축소만"(2026-10-02 사용자 결정)과 어긋나 있었다. 레시피는 누름(mousedown)을 막고 click 에서 고른다. 웹 제품 · 앱은 이미 그렇다.
  • Chip Tabs 의 칩 높이는 Chip 이 원본(Q-010-2, 정리) — chip-tabs.yaml 이 36 · 40 을 다시 적던 것을 chip.yaml 의 크기를 가리키는 줄로 바꿨다(값은 같다). 구현은 Chip Tabs 견본의 칩을 chip.json(size)으로 잰다.
  • 알림 점은 "새 소식" 하나로(Q-010-4, 사용자 결정 안 A) — Tabs · Chip Tabs 는 그대로다(Segmented Control 이 "새 내용" 에서 바뀐다). 앱은 호출부가 글을 넘기지 않고 컴포넌트가 "새 소식" 을 갖는다.

2026-10-04 — 가계부 묶음은 화면 위 Line

화면 틀 · 이동 비교 페이지 7A — 하단 탭 바는 어느 화면에서나 홈 · 가계부 · + · 캘린더 · 전체 그대로이고, 가계부 · 자산 · 통계 · 예산은 가계부 화면 위 1차 Line 이다(웹은 주소에). 지금 웹 · 앱이 탭 바 칸을 ← · 가계부 · 자산 · 통계 · 예산으로 바꾸던 것(7B)은 걷는다 — Bottom Navigation 의 Migration notes. 그 아래 통계의 카테고리 · 추이 · 비교는 폰에서 2차라 "두 단" 규칙대로다(2026-10-08 — 새 결정 없이 규칙으로 풀었다).

2026-10-02 — SEED Tabs 로 다시 정한다

사용자가 비교 페이지에서 정했다 — Tabs 는 구역 이동(1차 Line · 2차 Chip Tabs), 같은 내용 조작은 Segmented Control · Line 은 40 · 44 · 글 700 고정 · 고르면 글자색만 짙어지고 2px 중립색 막대가 미끄러진다(누름은 축소만) · 5개까지 Fill · 6개부터 Hug · 화살표로 옮기면 바로 고른다 · 내용은 바로 바꾸고 상태를 남긴다(폰 1차 탭 밀어 넘기기 · 웹 1차 탭은 주소에) · 글에 개수 없음 · 알림 점 하나. 옛 Tabs 의 세 모양(container · underline · pills)과 수동 활성화를 걷었다 — 옛 스펙은 tabs.history/v-pre-seed-tabs.*.

제품은 앱 적용 단계에서 옮긴다(2026-10-02 조사 — 세 제품 코드를 읽고 Desk 웹 · HR 은 크로미움에 띄워 쟀다). 탭처럼 생긴 자리 104곳(Desk 웹 49 · 앱 45 · HR 10) 중 구역 이동은 33곳이고, 같은 내용 조작 34곳은 Segmented Control · Chip, 폼 값 32곳은 Chip · Select 로 간다.

  • Desk 웹 — Radix Tabs 41곳이 모두 tablist 로 읽히지만 내용 칸이 없어 aria-controls 가 없는 id 를 가리킨다. 폼 값 탭(언어 · 이메일 주기)은 화살표마다 언어가 바뀌고 서버에 저장된다. 고른 표시가 회색 트랙 · 브랜드 채움 · 브랜드 밑줄 · status-info 채움 넷이고, 회색 트랙의 고른 칸은 트랙과 1.12 · 1.15:1 이다. 관심 그룹 탭은 스크롤이 없어 그룹 5개면 편집 버튼이 밀려난다. 탭 값이 화면 안 상태라 다른 메뉴를 다녀오거나 새로고침하면 처음 탭이다(주소에 남는 것은 증권사 경로 · 설정 ?section 둘).
  • Desk 앱 — PTabs 37 · PSegmented 2 · 손으로 만든 것 6, 의미 구조가 없고 키보드로 고른 탭에 닿지 못한다. 가계부 · 자산 · 통계 · 예산 사이를 오가면 통계 탭이 처음으로 돌아가고, 내보내기 ↔ 가져오기를 바꾸면 고른 파일이 사라진다. 계좌 종류 6칸 탭은 "마이너스통장" 이 말줄임된다(→ Select).
  • HR 웹 — Radix Tabs 6 정의 · 8곳, 내용 칸을 갖춘 진짜 탭은 여기뿐이다. 라이트에서 고른 · 안 고른 글자색이 같고, 회사 화면(모바일) 영어 글이 칸을 넘친다.
  • 앱 적용 때 화면마다 정할 자리 — 더치페이(진행 중 · 완료 · 친구), 관심 그룹, 호가 · 체결, 달력 · 목록, 차트 기간 5 · 캘린더 보기 5, HR 회사 모바일, HR 캘린더 필터 팝오버.

이 페이지