SegmentedButton
연결된 세그먼트 컨트롤 — single(라디오 그룹)·multi(토글) 선택. BadgeToggle을 정식화한 ADR-012 Track C 컴포넌트입니다.
마지막 업데이트 2026-06-30
한눈에#
연결된 세그먼트에서 단일(라디오) 또는 다중(토글)을 즉시 선택합니다.
- single · multi
- sm · md
- 옵션 2~5
- radiogroup / group
single — 화살표 키로 순환 이동하며 즉시 선택
사용 시점#
연결 트랙 2~5개 토글이면 SegmentedButton — 그 외에는 목적에 맞는 컴포넌트를 가리킵니다.
권장 — 이렇게 쓰세요
지양 — 이러지 마세요
쓴다 — 옵션 2~5개를 연결 트랙에서 즉시 토글 — 정렬·기간 단위
대신 Tabs — 콘텐츠 패널 전환 내비게이션
대신 RadioGroup — 세로로 펼친 폼 단일 선택
대신 BadgeToggle — '전체' 포함 필 형태 필터 줄
플레이그라운드#
컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.
변형#
selectionMode가 선택 방식을 가릅니다 — 'single'(기본)은 하나만 켜지는 라디오 그룹,
'multi'는 여러 개를 켜고 끄는 토글 그룹입니다.
크기#
size로 2단 — md(기본)·sm. 모든 세그먼트는 하나의 연결된 트랙을 공유하며, sm은 시각 32px이지만 ::after로 블록축 히트 영역을 44px까지 확장합니다.
상태#
비제어(defaultValue)와 제어(value)를 모두 지원합니다.
- 비제어 —
defaultValue로 시작하고 선택이 바뀔 때onChange로 알립니다. 이후 선택 상태는 컴포넌트가 소유합니다. - 제어 —
value(single은string, multi는readonly string[])를 주면 그 값이 진실의 원천입니다. 클릭/키보드는 내부 상태를 갱신하지 않고onChange로만 통지하므로, 소비자가value를 갱신해야 선택이 반영됩니다(URL·전역 상태 동기에 적합).
비활성 세그먼트는 disabled로 지정하며, single 모드의 화살표 이동은 비활성 세그먼트를
건너뜁니다. Hover/Focus/Disabled는 CSS 의사클래스로 표현됩니다. sm 세그먼트는 시각
높이 32px를 유지하면서 ::after로 블록축 히트 영역을 44px까지 확장합니다(터치 타깃).
single 모드의 선택 thumb는 이전 선택 rect와 다음 선택 rect의 거리(sqrt(dx² + dy²))를
계산해 정착 시간을 보정합니다. 가까운 세그먼트는 빠르게, 먼 세그먼트는 상한 안에서 조금 더
길게 움직여 같은 트랙 안의 속도감이 균일하게 유지됩니다. prefers-reduced-motion에서는
전환 없이 최종 위치로 즉시 스냅합니다.
Props#
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
options | readonly SegmentedButtonOption[] | — | 옵션 배열 { value, label, disabled? } — 데이터 prop 방식. |
selectionMode | 'single' | 'multi' | — | single: 라디오(하나) · multi: 토글(여러 개). |
value | string | readonly string[] | — | 제어 선택 값 — 제공하면 제어 모드(내부 상태 무시, 전환은 onChange로만 통지) 제어 선택 값 배열 — 제공하면 제어 모드(내부 상태 무시, 전환은 onChange로만 통지) |
defaultValue | string | readonly string[] | — | 초기 선택 값 — 이후 상태는 내부 소유(비제어, value 미제공 시) 초기 선택 값 배열 — 이후 상태는 내부 소유(비제어, value 미제공 시) |
onChange | ((value: string) => void) | ((values: readonly string[]) => void) | — | 선택 변경 — single은 (value), multi는 (values). |
size | 'sm' | 'md' | — | 컨트롤 크기 — md(기본) | sm |
ref | Ref<HTMLDivElement> | — | 루트 <div>로 전달되는 ref (React 19 ref-as-prop) |
접근성#
| 모드 | 계약 |
|---|---|
| single | 루트 role="radiogroup", 각 세그먼트 button[role="radio"] + aria-checked. roving tabindex(선택/첫 활성만 탭) · 화살표 순환 이동 + 즉시 선택 · 비활성 건너뜀 |
| multi | 루트 role="group", 각 세그먼트 토글 button + aria-pressed. 일반 Tab 순서 · Space/Enter/클릭으로 멤버십 토글 |
| 공통 | 그룹 이름은 aria-label 필수 · :focus-visible 2px primary 아웃라인 · 등장 전환은 prefers-reduced-motion 존중 |
토큰#
component 토큰 없이 semantic을 직접 소비합니다(신설 기준 §4 미충족).
| 속성 | 토큰 |
|---|---|
| 트랙 | color.surface · color.border · radius.control |
| 선택/눌림 세그먼트 | color.primary-subtle 배경 · color.primary-text |
눌림(:active, 미선택) | color.text 9% (color-mix 반투명 오버레이) |
| 크기 | control.height-md / control.height-sm · font.size-body-1 / body-2 |
| sm 히트 영역 | space.3 / 2(6px) 블록축 확장 → 32px 시각·44px 터치 |
| 선택 thumb 모션 | spring.spatial.fast 이징 + 거리 기반 duration을 런타임 인라인 오버라이드(폴백 --wds-spring-spatial-fast-duration) |
| 포커스 | color.focus-ring 2px 아웃라인 |
| 모션 | duration.fast + ease.standard |