ComponentsP3 본문

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를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

SegmentedButton를 직접 조작해 보세요

속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.

빌더 열기

플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.

변형#

selectionMode가 선택 방식을 가릅니다 — 'single'(기본)은 하나만 켜지는 라디오 그룹, 'multi'는 여러 개를 켜고 끄는 토글 그룹입니다.

multi — 여러 세그먼트를 동시에 선택

크기#

size로 2단 — md(기본)·sm. 모든 세그먼트는 하나의 연결된 트랙을 공유하며, sm은 시각 32px이지만 ::after로 블록축 히트 영역을 44px까지 확장합니다.

sm · md — 연결 트랙(높이는 control 토큰)
sizeheightfonthit areasm32px14px44pxmd44px16px

상태#

비제어(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타입기본값설명
optionsreadonly SegmentedButtonOption[]옵션 배열 { value, label, disabled? } — 데이터 prop 방식.
selectionMode'single' | 'multi'single: 라디오(하나) · multi: 토글(여러 개).
valuestring | readonly string[]제어 선택 값 — 제공하면 제어 모드(내부 상태 무시, 전환은 onChange로만 통지) 제어 선택 값 배열 — 제공하면 제어 모드(내부 상태 무시, 전환은 onChange로만 통지)
defaultValuestring | readonly string[]초기 선택 값 — 이후 상태는 내부 소유(비제어, value 미제공 시) 초기 선택 값 배열 — 이후 상태는 내부 소유(비제어, value 미제공 시)
onChange((value: string) => void) | ((values: readonly string[]) => void)선택 변경 — single은 (value), multi는 (values).
size'sm' | 'md'컨트롤 크기 — md(기본) | sm
refRef<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