Groo Design

Segmented Control

같은 내용을 2 ~ 4가지로 바로 거르거나 · 정렬하거나 · 다르게 보는 컨트롤. 그 내용 바로 위에, 한 화면에 하나 둔다. 다른 구역으로 옮기면 Tabs, 2 ~ 4개 짧은 폼 값은 Chip, 목록 조건을 여럿 걸고 풀면 Chip 의 필터 바다.

구조는 당근 SEED Segmented Control(Apache-2.0)을 따른다 — 트랙 · 칸 · 글 · 고른 알약. 칸 폭만 groo 가 다시 정했고(칸이 트랙을 똑같이 나눈다), 나머지 값은 groo 토큰이다. SEED 와 다른 자리는 맨 아래 "SEED 와 다른 점" 에 적었다(2026-10-02 사용자 결정).

수치 원본은 segmented-control.yaml이다. 수치 표 자리([표: …])와 그림 자리([그림: …])는 사이트가 그 파일로 그린다 — GitHub 에서는 그 파일 · 그림 코드로 가는 링크로 보인다.

9:41
가계부
전체지출수입
점점심 식사식비, 현대카드 M−12,000원
급급여수입, 국민은행+3,200,000원
스스타벅스카페, 현대카드 M−5,600원
지지하철교통, 국민 체크카드−1,450원
9:41
할 일
오늘이번 주전체완료
카드 대금 확인오늘
관리비 이체오늘
장보기10월 3일 (토)
가계부 · 할 일 — 라이트 · 다크

직접 골라 보기

칸 수 · 고른 칸 · 알림 점 · 막힌 칸 · 긴 글을 고르면 스펙대로 그린 컨트롤과 그 코드가 바뀐다. 실제로 누르고 화살표로 옮길 수 있다.

  • 점심 식사식비 · 현대카드 M−12,000원
  • 급여수입 · 국민은행+3,200,000원
  • 스타벅스카페 · 현대카드 M−5,600원
  • 지하철교통 · 국민 체크카드−1,450원
  • 중고 거래수입 · 토스뱅크 통장+25,000원
칸 수
고른 칸 value
알림 점 notification
막힌 칸 disabled
글
모드
브랜드
import { SegmentedControl, SegmentedControlItem } from "@/components/ui/segmented-control"

const [view, setView] = useState("all")

<SegmentedControl aria-label="가계부 보기" value={view} onValueChange={setView}>
  <SegmentedControlItem value="all">전체</SegmentedControlItem>
  <SegmentedControlItem value="expense">지출</SegmentedControlItem>
  <SegmentedControlItem value="income">수입</SegmentedControlItem>
</SegmentedControl>

Anatomy

전체지출수입새 소식
ⓐ Trackⓑ Segmentⓒ Labelⓓ Indicatorⓔ Notification
2배로 그렸다 — 고른 칸 뒤에 흰 알약, 셋째 칸에 알림 점
트랙 · 칸 · 글 · 고른 알약 · 알림 점
부위설명
ⓐ Track트랙 — 알약. 놓인 자리 폭을 채우고, 칸이 그 폭을 똑같이 나눈다.
ⓑ Segment칸 — 누르는 자리. 모든 칸이 같은 폭 · 같은 높이다.
ⓒ Label글 — 짧게. 길면 단어 단위로 줄을 바꾸고 모든 칸이 가장 높은 칸에 맞춘다.
ⓓ Indicator고른 알약 — 고른 칸 뒤에 깔리고, 다른 칸을 고르면 미끄러져 옮긴다.
ⓔ Notification알림 점 — 새 소식이 있는 칸에만, 글 오른쪽 위.

부위

부위설명
root트랙 — 알약. 놓인 자리 폭을 채우고 칸이 그 폭을 똑같이 나눈다
item칸 — 누르는 자리. 모든 칸이 같은 폭 · 같은 높이
label글 — 짧게. 길면 단어 단위로 줄을 바꾼다
indicator고른 알약 — 고른 칸 뒤에 깔리고, 다른 칸을 고르면 미끄러져 옮긴다
notification알림 점 — 새 소식이 있는 칸에만, 글 오른쪽 위
focusRing키보드 포커스 링(웹) — 칸 바깥

Properties

크기 · 변형이 하나다. 트랙 안쪽 4 + 칸 34 = 42, 글 16 · 700(고르든 안 고르든 — 글자 크기 설정을 따르지 않는 t5-static), 칸 좌우 12. 칸은 트랙 폭을 칸 수로 똑같이 나누고 최소 폭이 없어, 폰(콘텐츠 폭 312)에서도 4개가 들어간다. 넓은 화면에서는 트랙이 놓인 자리를 채우므로 자리를 좁혀 둔다.

국내미국
전체지출수입
오늘이번 주전체완료
360 폰 — 트랙 312(여백 24 × 2)칸 = (트랙 − 안쪽 4 × 2) ÷ 칸 수 — 최소 폭 없이 4개도 들어간다 · 높이 42 = 칸 34 + 안쪽 4 × 2 · 글 16 · 700 · 칸 좌우 12
폭 — 폰에서 2 · 3 · 4개

State

상태모습
enabled트랙 bg-neutral-weak-alpha(투명 — 어느 바탕에서나 보인다, v120) 위 안 고른 글 fg-neutral-subtle(다크는 fg-neutral-muted — 투명 트랙 위 4.5:1 을 지키려고, 2026-10-17 사용자 결정 — 01-040 B 후속), 고른 칸은 흰 알약(bg-layer-default + 안쪽 짙은 1px stroke-neutral-contrast) 위 fg-neutral
hovered웹 — 누름과 같은 바탕(축소 없음)
pressed안 고른 칸 bg-neutral-weak-pressed + 1px stroke-neutral-weak(글은 fg-neutral-muted), 고른 칸 bg-layer-default-pressed + 짙은 1px 그대로. 칸 바탕은 그대로 두고 안의 글만 2px 거리로 축소한다
focused키보드 포커스에만 링 2px · 띄움 2px — 칸 바깥
disabled글 fg-disabled · 커서 not-allowed — 흐리게 하지 않는다(v106). 고른 채 막히면 칸에 bg-disabled + 짙은 1px stroke-neutral-solid 를 남긴다
안 고름고름기본
국내미국
국내미국
호버(웹)
국내미국
국내미국
누름
국내미국
국내미국
포커스(키보드)
국내미국
국내미국
비활성
국내미국
국내미국
라이트앞 칸이 그 상태 — 호버는 누름과 같은 바탕(축소 없음) · 누름은 글만 축소 · 링은 칸 바깥 · 고른 채 막히면 회색 칸 + 1px
안 고름고름기본
국내미국
국내미국
호버(웹)
국내미국
국내미국
누름
국내미국
국내미국
포커스(키보드)
국내미국
국내미국
비활성
국내미국
국내미국
다크앞 칸이 그 상태 — 호버는 누름과 같은 바탕(축소 없음) · 누름은 글만 축소 · 링은 칸 바깥 · 고른 채 막히면 회색 칸 + 1px
상태 — 기본 · 호버 · 누름 · 포커스 · 비활성 × 안 고름 · 고름

상태 — 안 고름

상태item 배경item 테두리item 테두리 두께item 커서label 글자·아이콘label 배율label 축소 시간label 축소 곡선링 두께링 간격링 색
enabled 기본———pointercolor-fg-neutral-subtle #62697A · 다크 color-fg-neutral-muted #535866 — 다크는 한 단계 짙게 — 투명 트랙이 다크 표면에 섞여 밝아져 fg-neutral-subtle 이 카드 위 4.09 · 시트 위 3.56 이다. muted 는 카드 5.18 · 시트 4.50 · 바닥 5.93, 라이트는 subtle 그대로 4.59 ~ 4.95(2026-10-17 사용자 결정 — 01-040 B 후속)——————
hovered 웹 — 누름과 같은 바탕(v106), 축소는 없다color-bg-neutral-weak-pressed #EDEFF3 · 다크 #404757color-stroke-neutral-weak #E5E8EF · 다크 #404757 — 안쪽 1px — 고른 알약과 같은 테두리1pxpointercolor-fg-neutral-muted #535866 · 다크 #B7BDCC — 누름 바탕 위에서 한 단계 짙게 — fg-neutral-subtle 이면 다크 3.91:1, muted 4.95 · 라이트 6.17(List 의 강조 줄과 같은 방법)——————
pressed 누름 바탕 + 칸 안의 글만 2px 거리 축소(바탕은 그대로)color-bg-neutral-weak-pressed #EDEFF3 · 다크 #404757color-stroke-neutral-weak #E5E8EF · 다크 #4047571pxpointercolor-fg-neutral-muted #535866 · 다크 #B7BDCC글 2px 거리 축소 — 칸 바탕은 그대로, 안의 글만 준다(SEED scaleScope: content · v104) — 모션 줄이기면 하지 않는다motion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)———
focused 웹 — 키보드 포커스에만 링———pointercolor-fg-neutral-subtle #62697A · 다크 color-fg-neutral-muted #535866 — 다크는 한 단계 짙게 — 투명 트랙이 다크 표면에 섞여 밝아져 fg-neutral-subtle 이 카드 위 4.09 · 시트 위 3.56 이다. muted 는 카드 5.18 · 시트 4.50 · 바닥 5.93, 라이트는 subtle 그대로 4.59 ~ 4.95(2026-10-17 사용자 결정 — 01-040 B 후속)———2px2px — 칸 바깥 — 알약을 따라 둥글다color-stroke-focus-ring #1A1F2E · 다크 #F5F6FA
disabled 막힌 칸 · 막힌 트랙 — 전용 색(v106), 흐리게 하지 않는다———not-allowed — 누름 바탕 · 축소 없음color-fg-disabled #8A91A0 · 다크 #838997——————

상태 — 고름

상태item 배경item 테두리item 테두리 두께item 커서label 글자·아이콘label 배율label 축소 시간label 축소 곡선링 두께링 간격링 색
enabled 기본———pointercolor-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색만 바뀐다 — 굵기 · 크기 그대로——————
hovered 웹 — 누름과 같은 바탕(v106), 축소는 없다color-bg-layer-default-pressed #F7F8FD · 다크 #353B4D — 칸에 칠해 알약을 덮는다 — 짙은 테두리는 그대로color-stroke-neutral-contrast #1A1F2E · 다크 #F5F6FA1pxpointercolor-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색만 바뀐다 — 굵기 · 크기 그대로——————
pressed 누름 바탕 + 칸 안의 글만 2px 거리 축소(바탕은 그대로)color-bg-layer-default-pressed #F7F8FD · 다크 #353B4D — SEED palette.gray-100 의 역할 짝 — 짙은 테두리는 그대로color-stroke-neutral-contrast #1A1F2E · 다크 #F5F6FA1pxpointercolor-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색만 바뀐다 — 굵기 · 크기 그대로글 2px 거리 축소 — 칸 바탕은 그대로, 안의 글만 준다(SEED scaleScope: content · v104) — 모션 줄이기면 하지 않는다motion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)———
focused 웹 — 키보드 포커스에만 링———pointercolor-fg-neutral #1A1F2E · 다크 #F5F6FA — 글자색만 바뀐다 — 굵기 · 크기 그대로———2px2px — 칸 바깥 — 알약을 따라 둥글다color-stroke-focus-ring #1A1F2E · 다크 #F5F6FA
disabled 막힌 칸 · 막힌 트랙 — 전용 색(v106), 흐리게 하지 않는다color-bg-disabled #F5F6FA · 다크 #353B4D — 고른 채 막힘 — 칸에 칠해 알약을 덮는다color-stroke-neutral-solid #767C8B · 다크 #838997 — 짙은 1px 를 회색으로 남겨 무엇을 골랐는지 보인다(Chip 의 고른 채 막힘과 같다)1pxnot-allowed — 누름 바탕 · 축소 없음color-fg-disabled #8A91A0 · 다크 #838997——————

공통

부위속성값비고
root여백spacing-x1 4px
root모서리radius-full 9999px
root배경color-bg-neutral-weak-alpha #0000000C · 다크 #FFFFFF20SEED 그대로 투명(검정 4.7% · 다크 흰 12.5%) — 놓인 바탕에 섞여 회색 바닥 · 흰 면 위 1.11 · 다크 1.47:1(v120)
root너비놓인 자리 폭트랙이 자리를 채우고 칸 수로 똑같이 나눈다(최소 폭 없음) — 넓은 화면에서는 놓는 자리를 좁힌다. 머리 오른쪽 자리(카드 · 구역 머리)에서는 내용 폭 = (가장 긴 칸 글 + 칸 좌우 12 · 12) × 칸 수 + 트랙 안쪽 4 · 4 — 칸 글이 글자 크기를 따르지 않아(t5-static) 폭이 흔들리지 않는다. 제목이 머리 폭의 50% 이상을 지키지 못하면 머리 아래 줄 오른쪽 끝으로 내려간다(2026-10-25 08-2 — 웹 · 앱이 이 규칙으로 맞췄다)
root칸 수칸 수(2 ~ 4)모든 칸이 같은 폭 · 같은 높이(가장 높은 칸에 맞춘다)
item최소 높이34px트랙 안쪽 4 를 더해 42
item좌우 여백spacing-x3 12pxSEED 24 → 12 — 칸이 트랙을 나누므로 폰에서 4개도 들어간다
item상하 여백spacing-x1_5 6px
item모서리radius-full 9999px
item커서pointer
item터치 영역칸 전체34 × 칸 폭 — AA ✓(24 이상) · AAA 는 44 에 모자란다(SEED 와 같다)
item전환 대상background-color, color, box-shadow
item전환 시간motion-duration-color-transition 150ms
item전환 곡선motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)
label글자text-t5-static 16px / 22px16 / 22 — 고르든 안 고르든 같다. -static — 글자 크기 설정을 따르지 않는다(웹 text-t5-static, 앱 TextScaler.noScaling). 큰 글자에서 4칸이 "오 / 늘" 처럼 한 글자씩 쪼개지지 않게 — WCAG 1.4.4 의 예외(하단 탭 라벨과 같은 대가, 2026-10-17 사용자 결정 — 03-B 결정 4 A. 2 × 2 격자는 고르지 않았다)
label굵기700고르든 안 고르든 700
label글자·아이콘color-fg-neutral-subtle #62697A · 다크 color-fg-neutral-muted #535866다크는 한 단계 짙게 — 투명 트랙이 다크 표면에 섞여 밝아져 fg-neutral-subtle 이 카드 위 4.09 · 시트 위 3.56 이다. muted 는 카드 5.18 · 시트 4.50 · 바닥 5.93, 라이트는 subtle 그대로 4.59 ~ 4.95(2026-10-17 사용자 결정 — 01-040 B 후속)
label글 맞춤center길면 단어 단위로 줄을 바꾼다(v114)
indicator배경color-bg-layer-default #FFFFFF · 다크 #242938흰 알약 — 다크에서는 트랙보다 어둡다(SEED 도 다크 알약이 검정)
indicator테두리color-stroke-neutral-contrast #1A1F2E · 다크 #F5F6FA안쪽 1px(inset) 짙은 테두리 — 고른 칸을 트랙과 라이트 13.71 ~ 14.79 · 다크 7.84 ~ 10.33:1 로 가른다(SEED 옅은 1px 은 1.14 · 1.20 — 사용자 결정 2026-10-02)
indicator테두리 두께1px
indicator모서리radius-full 9999px
indicator알약 들임4px트랙 안쪽 4 — 폭 = (트랙 − 8) ÷ 칸 수, 고른 칸 번호만큼 옆으로 옮긴다
indicator전환 대상transform고른 칸으로 미끄러진다
indicator전환 시간motion-duration-d4 200ms
indicator전환 곡선motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)
notification크기6px
notification모서리radius-full 9999px
notification배경color-fg-brand HR #075B3C · Desk #0147AD브랜드 글자색 — 트랙 위 Desk 라이트 7.00 ~ 7.55 · 다크 3.56 ~ 4.69 · HR 6.82 ~ 7.36 · 3.55 ~ 4.67(v120 투명 트랙 — 놓인 바탕에 따라, bg-brand-solid 는 다크에서 Desk · HR 1.33 이라 안 보인다). 고른 칸에는 없다 — 고르면 사라진다
notification간격2px글 끝에서 2, 글 위쪽에 맞춘다

모션

전환시간곡선대상비고
고른 알약 — 미끄러짐motion-duration-d4 200msmotion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)transform
누름 · 호버 · 고름 — 색motion-duration-color-transition 150msmotion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)background-color, color, box-shadow
누름 — 글motion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)scale칸 안의 글만 2px 거리 축소 — 모션 줄이기면 하지 않는다

Guidelines

같은 내용을 바로 바꿀 때

Segmented Control 은 조작이다 — 고르면 화면의 그 내용만 바로 거르거나 · 정렬하거나 · 다르게 보인다(프리셋을 많이 쓴 순 · 최근 사용 · 이름순으로, 더치페이를 진행 중 · 완료 · 친구로). 다른 구역 · 페이지로 옮기는 탐색에는 쓰지 않는다 — 그건 Tabs 다. 저장할 폼 값도 아니다 — 폼 값은 Chip · Select.

9:41
가계부
전체지출수입
점점심 식사식비, 현대카드 M−12,000원
급급여수입, 국민은행+3,200,000원
스스타벅스카페, 현대카드 M−5,600원
지지하철교통, 국민 체크카드−1,450원
이렇게 — 같은 내용을 다르게 보기 — 가계부 목록을 전체 · 지출 · 수입으로, 그 목록 바로 위에서 바로 거른다
9:41
통계
카테고리추이비교
10월 지출412,300원
식식비44%182,400원
쇼쇼핑22%89,000원
카카페13%52,300원
이렇게 하지 않는다 — 다른 구역으로 옮기기 — 카테고리 · 추이 · 비교는 내용 전체가 바뀌는 구역이라 화면 맨 위 Tabs 다
쓰임 — 같은 내용을 다르게 보기 · 다른 구역으로 옮기기

비슷한 셋은 이렇게 견준다. 폼 값 · 설정 값을 고르는 표는 Select 의 "고르는 컴포넌트 고르기" 한 곳이다(2026-10-22 사용자 결정 1B — https://claude.ai/artifact/SmHD31RQxTjWbfK83nbcym).

Segmented ControlChip 필터 바Tabs
핵심 용도같은 내용을 거르기 · 정렬 · 다르게 보기조건을 여럿 걸고 푼다다른 구역 · 화면으로 옮긴다
위치바꾸는 내용 바로 위목록 위 한 줄(가로 스크롤 · 끝 흐림)화면 · 구역 맨 위
영향 범위그 내용만그 목록만아래 전체를 바꾼다
개수2 ~ 4(사용자 결정)정해지지 않음 · 개수가 바뀐다1차 Fill 5개까지
한 화면에하나(사용자 결정) — 둘째 축은 Chip 하나 고르기 · Select하나1차 하나 + 2차 Chip Tabs

내용 바로 위에, 한 화면에 하나

자기가 바꾸는 내용 바로 위에 둔다 — 떨어져 있으면 무엇을 바꾸는지 알 수 없다. 한 화면에 하나만 둔다. 같은 모양이 둘이면 어느 것이 어느 내용을 바꾸는지 헷갈린다 — 둘째 축은 Chip(하나 고르기) · Select 로 둔다.

9:41
할 일
오늘이번 주전체완료
카드 대금 확인오늘
관리비 이체오늘
이렇게 — 바꾸는 목록 바로 위에 하나 — 무엇을 거르는지 바로 보인다
9:41
증권
나무증권토스증권
보유관심발견
급상승급하락거래량
국내미국
삼삼성전자1위712,000원
SSK하이닉스2위621,000원
이렇게 하지 않는다 — 한 화면에 둘(토스 발견) — 어느 것이 어느 내용을 바꾸는지 헷갈린다. 둘째 축은 Chip(하나 고르기) · Select 로
자리 — 내용 바로 위 하나 · 한 화면에 둘

머리 오른쪽에 둘 때

카드 · 구역 머리의 오른쪽(제목과 같은 줄)에 두면 트랙이 자리를 채우지 않고 내용 폭이다 — 모든 칸이 가장 긴 칸 글에 칸 좌우 여백을 더한 같은 폭이고, 트랙은 그 칸들에 안쪽 여백을 더한 폭이다(셈은 segmented-control.yaml 의 root.width 비고). 칸 글은 글자 크기를 따르지 않으므로 큰 글자에서도 폭이 그대로다. 제목은 머리 폭의 절반 이상을 지킨다 — 그 자리가 남지 않으면 Segmented 가 머리 아래 줄 오른쪽 끝으로 내려간다. List 목록 제목 · Card 머리 동작의 반 폭 판정과 같은 결이다(2026-10-25 08-2 — 통계 고정 탭 월별 "지출 · 수입", 웹 · 앱이 이 규칙으로 맞췄다). 머리 오른쪽에 둬도 "자기가 바꾸는 내용 바로 위" 다 — 머리 아래가 곧 그 내용일 때만 둔다.

2 ~ 4개, 글은 짧게

칸은 2 ~ 4개다. 5개 이상이면 Chip 의 하나 고르기 줄 · Select 로 둔다. 글은 짧게("이름순" · "최근 사용") — 칸에 비해 글이 길면 줄이 바뀌어 모든 칸이 높아진다. 그러면 다른 컴포넌트를 쓴다.

9:41
자산 추이
3개월6개월1년
순자산55,200,000원
이렇게 — 짧은 명사 — "3개월 · 6개월 · 1년" 처럼 한 줄에 들어간다
9:41
프리셋
사용 횟수가 많은 순최근에 사용한 순이름 가나다순
점점심 식사식비, 현대카드 M12,000원
아아침 커피카페, 현대카드 M4,500원
출출퇴근교통, 국민 체크카드1,450원
이렇게 하지 않는다 — 문장처럼 길게 — 줄이 바뀌어 모든 칸이 높아진다. 이러면 다른 컴포넌트를 쓴다
글 — 짧게 · 길어서 두 줄

코드

레시피 recipes/shadcn/components/ui/segmented-control.tsx 를 쓴다(라디오 묶음 — 화살표로 옮기면 바로 고른다). 이름은 aria-label 로 단다. 늘 하나가 골라져 있어야 하므로 value(또는 defaultValue)를 준다. 아래 미리보기는 스펙 값으로 그린 모습이다.

  • 카드 대금 확인오늘
  • 관리비 이체오늘
import { SegmentedControl, SegmentedControlItem } from "@/components/ui/segmented-control"

<SegmentedControl aria-label="할 일 보기" value={view} onValueChange={setView}>
  <SegmentedControlItem value="today">오늘</SegmentedControlItem>
  <SegmentedControlItem value="week">이번 주</SegmentedControlItem>
  <SegmentedControlItem value="all">전체</SegmentedControlItem>
  <SegmentedControlItem value="done">완료</SegmentedControlItem>
</SegmentedControl>

Behavior

인터랙션동작
Click · Tap그 칸을 고르고 내용을 바로 바꾼다. 고른 알약이 200ms 로 미끄러진다. 고른 칸을 다시 눌러도 그대로다.
← → · ↑ ↓이웃 칸으로 옮기며 바로 고른다(라디오). 막힌 칸은 건너뛴다.
Home · End받지 않는다 — 초점도 고른 칸도 그대로, 화면도 스크롤되지 않는다(PageUp · PageDown 도). 첫 · 끝 칸으로는 화살표로 간다 — SEED · 진짜 라디오 · WAI-ARIA APG Radio Group 과 같다(2026-10-17 사용자 결정 — 03-E 결정 3 A). Tabs 는 Home · End 로 옮기며 고른다.
Tab고른 칸 하나에만 선다.
마우스 호버누름과 같은 바탕(축소 없음).
Disabled칸 하나 또는 트랙 전체를 막는다 — 누를 수 없다 · 커서 not-allowed · 화살표 이동에서 건너뛴다.

Accessibility

기준검증
WCAG 1.4.3 Color contrast(글자 ≥ 4.5:1)안 고른 글 fg-neutral-subtle 트랙 위 — 트랙이 투명해 놓인 바탕에 따라 다르다(v120): 라이트 흰 면 4.95 · 회색 바닥 4.59, 다크 바닥 4.68 ✓ · 다크는 fg-neutral-muted 로 한 단계 짙게 — 다크 카드(bg-layer-default) 5.18 · 다크 시트(bg-layer-floating) 4.50 · 다크 바닥 5.93 ✓(subtle 이면 4.09 · 3.56 — 2026-10-17 사용자 결정 — 01-040 B 후속). 올리거나 누르는 동안 fg-neutral-muted 6.17 · 4.95, 고른 글 fg-neutral 알약 위 16.41 · 13.42 · 누름 15.48 · 10.32 ✓. 비활성 fg-disabled 는 기준 밖(비활성 UI)
WCAG 1.4.11 Non-text contrast(≥ 3:1)고른 칸은 알약의 짙은 1px stroke-neutral-contrast(트랙과 라이트 13.71 ~ 14.79 · 다크 7.84 ~ 10.33) ✓ — SEED 의 옅은 1px(1.14 · 1.20)을 바꿨다. 고른 채 막힘 stroke-neutral-solid 은 bg-disabled 위 3.87 · 3.18 ✓(비활성이라 기준 밖). 키보드 포커스 링 Desk 8.38 · 6.10 · HR 8.17 · 6.07 ✓. 알림 점 fg-brand 트랙 위 Desk 라이트 7.00 ~ 7.55 · 다크 3.56 ~ 4.69 · HR 라이트 6.82 ~ 7.36 · 다크 3.55 ~ 4.67 ✓ — 고른 칸에는 그리지 않는다
WCAG 1.4.4 Resize text칸 글은 예외다 — t5-static 16 이라 글자 크기 설정을 따르지 않는다(웹 text-t5-static · 앱 TextScaler.noScaling). 칸이 트랙을 나눠 폰 4칸이 76(글 자리 52)이라, 200% 에서 "오 / 늘" · "이 / 번 / 주" 처럼 한 글자씩 세로로 읽혔다. 하단 탭 라벨과 같은 대가(DESIGN v104 -static 목록, 2026-10-17 사용자 결정 — 03-B 결정 4 A). 큰 글자에서 2 × 2 격자로 바꾸는 안은 고르지 않았다
WCAG 2.4.7 Focus visible키보드 포커스에 링 2px · 띄움 2px — 칸 바깥
WCAG 2.5.8 Target Size — Minimum(AA ≥ 24×24)칸 34 × 칸 폭 ✓(폰 4개면 칸 폭 76)
WCAG 2.5.5 Target Size — Enhanced(AAA ≥ 44×44)칸 34 ✗(SEED 와 같다)
ARIA트랙 role="radiogroup" + aria-label, 칸은 라디오(aria-checked) — 고른 칸만 tabindex="0". 막힌 칸 disabled. 알림 점은 보조 기술에 "새 소식" 을 덧붙인다(점만으로 알리지 않는다 — Tabs · Chip Tabs · 하단 탭 바와 같은 말, 2026-10-15 사용자 결정 — 구현 세션 질문 Q-010-4, 안 A)

Do / Don't

✅ Do

  • 같은 내용을 2 ~ 4가지로 바로 바꾸는 자리에 쓰고, 그 내용 바로 위에 둔다.
  • 한 화면에 하나.
  • 글은 짧게.
  • 늘 하나를 골라 둔다.

❌ Don't

  • 다른 구역 · 페이지로 옮기는 데 쓰기(Tabs).
  • 저장할 폼 값으로 쓰기(Chip · Select).
  • 한 화면에 둘 이상.
  • 5개 이상 · 긴 글.

Specification

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

Base

부위상태속성값
rootenabled너비width놓인 자리 폭트랙이 자리를 채우고 칸 수로 똑같이 나눈다(최소 폭 없음) — 넓은 화면에서는 놓는 자리를 좁힌다. 머리 오른쪽 자리(카드 · 구역 머리)에서는 내용 폭 = (가장 긴 칸 글 + 칸 좌우 12 · 12) × 칸 수 + 트랙 안쪽 4 · 4 — 칸 글이 글자 크기를 따르지 않아(t5-static) 폭이 흔들리지 않는다. 제목이 머리 폭의 50% 이상을 지키지 못하면 머리 아래 줄 오른쪽 끝으로 내려간다(2026-10-25 08-2 — 웹 · 앱이 이 규칙으로 맞췄다)
여백paddingspacing-x14px
칸 수columns칸 수(2 ~ 4)모든 칸이 같은 폭 · 같은 높이(가장 높은 칸에 맞춘다)
모서리radiusradius-full9999px(알약)
배경backgroundbg-neutral-weak-alpha#0000000C다크 #FFFFFF20SEED 그대로 투명(검정 4.7% · 다크 흰 12.5%) — 놓인 바탕에 섞여 회색 바닥 · 흰 면 위 1.11 · 다크 1.47:1(v120)
itemenabled최소 높이minHeight34px트랙 안쪽 4 를 더해 42
상하 여백paddingYspacing-x1_56px
좌우 여백paddingXspacing-x312pxSEED 24 → 12 — 칸이 트랙을 나누므로 폰에서 4개도 들어간다
모서리radiusradius-full9999px(알약)
커서cursorpointer
터치 영역touchTarget칸 전체34 × 칸 폭 — AA ✓(24 이상) · AAA 는 44 에 모자란다(SEED 와 같다)
전환 대상transitionPropertybackground-color, color, box-shadow
전환 시간transitionDurationmotion-duration-color-transition150ms
전환 곡선transitionEasingmotion-ease-easingcubic-bezier(0.35, 0, 0.35, 1)
labelenabled글자·아이콘foregroundfg-neutral-subtle#62697A다크 #A2A8B7다크 fg-neutral-muted#535866다크 #B7BDCC다크는 한 단계 짙게 — 투명 트랙이 다크 표면에 섞여 밝아져 fg-neutral-subtle 이 카드 위 4.09 · 시트 위 3.56 이다. muted 는 카드 5.18 · 시트 4.50 · 바닥 5.93, 라이트는 subtle 그대로 4.59 ~ 4.95(2026-10-17 사용자 결정 — 01-040 B 후속)
글자typographytext-t5-static16 / 22 — 고르든 안 고르든 같다. -static — 글자 크기 설정을 따르지 않는다(웹 text-t5-static, 앱 TextScaler.noScaling). 큰 글자에서 4칸이 "오 / 늘" 처럼 한 글자씩 쪼개지지 않게 — WCAG 1.4.4 의 예외(하단 탭 라벨과 같은 대가, 2026-10-17 사용자 결정 — 03-B 결정 4 A. 2 × 2 격자는 고르지 않았다)
굵기fontWeight700고르든 안 고르든 700
글 맞춤textAligncenter길면 단어 단위로 줄을 바꾼다(v114)
indicatorenabled모서리radiusradius-full9999px(알약)
배경backgroundbg-layer-default#FFFFFF다크 #242938흰 알약 — 다크에서는 트랙보다 어둡다(SEED 도 다크 알약이 검정)
테두리borderColorstroke-neutral-contrast#1A1F2E다크 #F5F6FA안쪽 1px(inset) 짙은 테두리 — 고른 칸을 트랙과 라이트 13.71 ~ 14.79 · 다크 7.84 ~ 10.33:1 로 가른다(SEED 옅은 1px 은 1.14 · 1.20 — 사용자 결정 2026-10-02)
테두리 두께borderWidth1px
전환 대상transitionPropertytransform고른 칸으로 미끄러진다
전환 시간transitionDurationmotion-duration-d4200ms
전환 곡선transitionEasingmotion-ease-easingcubic-bezier(0.35, 0, 0.35, 1)
알약 들임inset4px트랙 안쪽 4 — 폭 = (트랙 − 8) ÷ 칸 수, 고른 칸 번호만큼 옆으로 옮긴다
notificationenabled크기size6px
간격gap2px글 끝에서 2, 글 위쪽에 맞춘다
모서리radiusradius-full9999px(알약)
배경backgroundfg-brandDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84브랜드 글자색 — 트랙 위 Desk 라이트 7.00 ~ 7.55 · 다크 3.56 ~ 4.69 · HR 6.82 ~ 7.36 · 3.55 ~ 4.67(v120 투명 트랙 — 놓인 바탕에 따라, bg-brand-solid 는 다크에서 Desk · HR 1.33 이라 안 보인다). 고른 칸에는 없다 — 고르면 사라진다
labelpressed배율scale글 2px 거리 축소칸 바탕은 그대로, 안의 글만 준다(SEED scaleScope: content · v104) — 모션 줄이기면 하지 않는다
축소 시간scaleDurationmotion-duration-pressed-scale150ms
축소 곡선scaleEasingmotion-ease-pressed-scalecubic-bezier(0, 0, 0.15, 1)
focusRingfocused링 두께width2px
링 색colorstroke-focus-ringDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84
링 간격offset2px칸 바깥 — 알약을 따라 둥글다
itemdisabled커서cursornot-allowed누름 바탕 · 축소 없음
labeldisabled글자·아이콘foregroundfg-disabled#8A91A0다크 #838997

selected=unselected

부위상태속성값
itemhovered배경backgroundbg-neutral-weak-pressed#EDEFF3다크 #404757
테두리borderColorstroke-neutral-weak#E5E8EF다크 #404757안쪽 1px — 고른 알약과 같은 테두리
테두리 두께borderWidth1px
labelhovered글자·아이콘foregroundfg-neutral-muted#535866다크 #B7BDCC누름 바탕 위에서 한 단계 짙게 — fg-neutral-subtle 이면 다크 3.91:1, muted 4.95 · 라이트 6.17(List 의 강조 줄과 같은 방법)
itempressed배경backgroundbg-neutral-weak-pressed#EDEFF3다크 #404757
테두리borderColorstroke-neutral-weak#E5E8EF다크 #404757
테두리 두께borderWidth1px
labelpressed글자·아이콘foregroundfg-neutral-muted#535866다크 #B7BDCC

selected=selected

부위상태속성값
labelenabled글자·아이콘foregroundfg-neutral#1A1F2E다크 #F5F6FA글자색만 바뀐다 — 굵기 · 크기 그대로
itemhovered배경backgroundbg-layer-default-pressed#F7F8FD다크 #353B4D칸에 칠해 알약을 덮는다 — 짙은 테두리는 그대로
테두리borderColorstroke-neutral-contrast#1A1F2E다크 #F5F6FA
테두리 두께borderWidth1px
itempressed배경backgroundbg-layer-default-pressed#F7F8FD다크 #353B4DSEED palette.gray-100 의 역할 짝 — 짙은 테두리는 그대로
테두리borderColorstroke-neutral-contrast#1A1F2E다크 #F5F6FA
테두리 두께borderWidth1px
itemdisabled배경backgroundbg-disabled#F5F6FA다크 #353B4D고른 채 막힘 — 칸에 칠해 알약을 덮는다
테두리borderColorstroke-neutral-solid#767C8B다크 #838997짙은 1px 를 회색으로 남겨 무엇을 골랐는지 보인다(Chip 의 고른 채 막힘과 같다)
테두리 두께borderWidth1px

SEED 와 다른 점

  • 칸이 트랙 폭을 똑같이 나눈다 — SEED 는 칸 최소 86 · 좌우 24 라 4개(352)가 360 · 375 폰에 들어가지 않는다(SEED 안에서 2 ~ 4개를 허용하는 규칙과 어긋난다). groo 는 최소 폭 없이 칸 수로 나누고 좌우 12 다 — 높이 · 글 · 알약은 SEED 그대로(사용자 결정 2026-10-02).
  • 반투명 색을 불투명 짝으로(v102) — 안 고른 칸 누름 테두리 stroke-neutral-weak. 트랙은 SEED 그대로 투명한 bg-neutral-weak-alpha 다 — v102 에는 검사기가 8자리 hex 를 받지 않아 불투명 bg-neutral-weak 로 두었는데, 회색 바닥 위에서 트랙이 바닥과 같은 색(1.00:1)이라 흰 알약만 떠 보여 v120 에 되돌렸다(2026-10-16 사용자 결정 — 기초 웹 01-040 B). 고른 알약은 SEED palette.gray-00(라이트 흰 · 다크 검정) 대신 bg-layer-default — 다크에서도 트랙보다 어둡다. 고른 칸 누름은 bg-layer-default-pressed.
  • 고른 알약의 테두리를 짙게 — SEED 의 옅은 1px(stroke.neutral-muted)는 트랙과 1.14:1 이라 고른 칸이 WCAG 1.4.11 에 못 미친다. 짙은 1px stroke-neutral-contrast(트랙과 라이트 13.71 ~ 14.79 · 다크 7.84 ~ 10.33:1)로 바꿨다 — Chip(Outline Weak 고름) · Select Box 의 고른 표시와 같은 말이다. 고른 채 막히면 stroke-neutral-solid(사용자 결정 2026-10-02).
  • 안 고른 칸을 올리거나 누르는 동안 글을 fg-neutral-muted 로 — 누름 바탕 위 fg-neutral-subtle 이 다크에서 3.91:1 이라서다(List 의 강조 줄과 같은 방법).
  • 다크의 안 고른 글은 늘 fg-neutral-muted — SEED 는 fg.neutral-subtle 이다. 투명 트랙(v120)이 다크 표면에 섞여 밝아지면서 subtle 이 카드 위 4.09 · 시트 위 3.56 이 돼, 다크만 한 단계 짙게 둔다(카드 5.18 · 시트 4.50). 라이트는 subtle 그대로(4.59 ~ 4.95)다(2026-10-17 사용자 결정 — 01-040 B 후속).
  • 줄바꿈은 단어 단위(v114) — SEED 는 글자 단위(overflow-wrap: break-word)다.
  • 알림 점은 브랜드 글자색(fg-brand)이고, 보조 기술에 "새 소식" 을 덧붙인다. SEED 의 bg.brand-solid 짝은 groo 다크에서 트랙과 Desk · HR 1.33:1 이라 쓰지 않는다. 고른 칸에는 점을 그리지 않는다.

Migration notes

2026-10-30 — 머리 오른쪽에 둘 때는 내용 폭

통계 고정 탭(08-2)에서 웹 · 앱이 맞춘 규칙을 적었다 — 머리 오른쪽 Segmented 는 내용 폭 = (가장 긴 칸 글 + 24) × 칸 수 + 8, 제목 50% 를 지키고 넘치면 머리 아래 오른쪽 끝. 셈은 segmented-control.yaml root.width 비고에 두고 md 에는 규칙만 적었다. 값 · 토큰 변경 없음 — 레시피에 따로 크기 축을 두지 않고 놓는 자리가 내용 폭 상자(웹 w-max max-w-full)로 감싼다. 옛 스펙은 segmented-control.history/v-pre-cleanup-1030.*.

2026-10-22 — Chip 필터 바 · Tabs 와 견주는 표

Segmented Control · Chip 필터 바 · Tabs 를 견주는 표를 두고, 폼 · 설정 값 고르기는 Select 의 "고르는 컴포넌트 고르기" 로 링크한다(사용자 결정 1B — https://claude.ai/artifact/SmHD31RQxTjWbfK83nbcym). 2 ~ 4 · 한 화면 하나는 10-02 결정 그대로다. 값 변경 없음.

2026-10-17 — 칸 글은 -static(03-B 결정 4 A)

웹 · 앱 칸 글이 글자 크기 설정을 따라 200% 에서 32 가 되어 4칸이 한 글자씩 쪼개졌다(조사 03B-007 — 앱 p_segmented_control.dart, 웹 segmented-control-variants.ts:21 text-t5). 사용자가 비교 페이지에서 "칸 글은 -static 16"(A)을 골랐다 — segmented-control.yaml label $text-t5-static, DESIGN v104 의 -static 목록에 "Segmented 칸 글". 레시피 · 예제 text-t5-static, 미리보기 --text-t5-static. 웹 ds 는 text-t5-static, 앱은 칸 글에 TextScaler.noScaling. 옛 스펙은 segmented-control.history/v-pre-03e-03b.md.

2026-10-17 — 하나 고르기 묶음은 Home · End 를 받지 않는다(03-E 결정 3 A)

웹 공용 라디오 묶음(Chip 하나 고르기 · Radio Group · Segmented Control · Select Box 하나 고르기 · List 라디오)은 Radix RovingFocusGroup 이 Home · End(· PageUp · PageDown)로 초점만 첫 · 끝으로 옮겨 초점과 고른 것이 갈렸다. 사용자가 비교 페이지에서 "받지 않는다"(A — 화살표만, SEED · 진짜 라디오 · APG)를 골랐다. 레시피는 묶음이 캡처 단계에서 라디오의 그 키를 막는다(ignoreRadioJumpKeys — radio-group.tsx, Segmented Control 도 쓴다). 웹 ds 의 같은 묶음도 같게, 앱은 바뀌는 것 없음. 옮기며 고르는 안(B — Tabs 처럼)은 고르지 않았다. 옛 스펙은 segmented-control.history/v-pre-03e-03b.md.

2026-10-15 — 알림 점은 "새 소식"

구현 세션 질문 Q-010-4 — 알림 점에 덧붙이는 글이 Tabs 는 "새 소식", Segmented Control 은 "새 내용" 으로 갈려 있었다. 사용자가 "새 소식" 하나로 골랐다(안 A — 컴포넌트마다 따로(B) · "새 내용" 으로 맞추기(C)는 고르지 않았다). 웹은 segmented-control.tsx 의 숨은 글을 바꾸고, 앱은 호출부가 notificationLabel 로 넘기던 글을 컴포넌트가 갖는다("새 소식").

2026-10-02 — 새로 둔다(SEED Segmented Control)

사용자가 비교 페이지에서 Tabs 와 나눠(구역 이동은 Tabs · 같은 내용 조작은 Segmented Control) SEED 모양을 고르고, 칸 폭만 "트랙에 맞춰 똑같이 나눈다"(B)로 정했다. 옛 Tabs 의 container · pills 모양이 하던 거르기 · 정렬 · 보기 자리를 맡는다.

제품은 앱 적용 단계에서 옮긴다(2026-10-02 조사). 같은 내용 조작 34곳(Desk 웹 17 · 앱 16 · HR 1) 중 2 ~ 4개는 Segmented Control, 그보다 많으면 Chip(하나 고르기) · Select 로 간다.

  • Desk 웹 · 앱 — 회색 트랙 탭(웹 26 · 앱 23)이 높이 28 ~ 34 · 모서리 2 ~ 8 · 글 12 ~ 13 · 500 이고, 고른 칸과 트랙이 1.12 · 1.15:1 이다. 다크에서는 고른 칸이 트랙보다 어둡다. 할 일 "오늘 · 이번 주 · 전체 · 완료" 처럼 4개를 폰에 쓰는 자리가 있다.
  • Desk 증권(토스 발견) — 보유 · 관심 · 발견 + 급상승 · 급하락 · 거래량 + 국내 · 미국이 같은 회색 트랙으로 셋 쌓인다 — 한 화면 하나 규칙에 걸려 앱 적용 때 나눈다.
  • HR 웹 — 보기 전환 버튼 묶음 1곳이 고른 상태를 알리지 않고 칸마다 Tab 이 선다.

이 페이지