Switch
토글 스위치 — button[role="switch"] + aria-checked. 라벨(children)은 label로 감싸 클릭 연동, 24px 트랙에 44px 히트 영역. 제어(checked)·비제어(defaultChecked) 모두 지원.
마지막 업데이트 2026-06-11
한눈에#
트랙·라벨 어느 쪽을 눌러도 토글되는 즉시-적용 on/off 컨트롤입니다.
- role=switch
- 즉시 적용
- 2 크기(md·sm)
- 44px 히트 영역
저장 버튼 없이 상태가 바로 반영됩니다 — 썸은 장식, 진실은 aria-checked
사용 시점#
켜는 즉시 적용되는 단일 on/off면 Switch — 제출 전 보류·혼합 상태면 Checkbox입니다.
다크 모드·알림 수신처럼 저장 없이 즉시 반영되는 단일 on/off 설정
플레이그라운드#
컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.
import { Switch } from '@wds/ui-web';
<Switch>다크 모드</Switch>해부#
트랙·썸·히트 영역 위에 토큰 실측을 핀으로 얹습니다 — 썸은 장식, 진실은 aria-checked입니다.
- track
- 44 × 24px
- thumb
- 18px
- thumb travel
- 20px
- radius
- full
radius.full - border
- 1px
border-strong - gap
- 8px
space-2 - label
- 16px
body-1 - hit area
- 44px
control.height-md
변형#
라벨이 없으면 aria-labelledby 연결도 생략되므로 aria-label을 직접
부여해야 합니다.
크기#
size로 2단(ADR-012 B-P2) — md(기본) 44×24px 트랙 + 18px 썸, sm 36×20px 트랙
- 14px 썸. 두 크기 모두 시각 트랙과 무관하게 히트 영역이
control.height-md(44px)로 확장되어 터치 타깃을 보장합니다.
상태#
- Checked — 트랙이
color.primary로 채워지고 썸이 우측으로 이동 - Focus — 트랙
:focus-visible에 2px primary 아웃라인 - Disabled —
color.surface-muted트랙 + 커서 차단
제어 · 비제어#
checked를 넘기지 않으면 비제어 — defaultChecked로 시작해 내부 상태가
on/off를 소유합니다. checked를 넘기면 제어 — 그 값이 진실의 원천이 되고
토글은 내부 상태를 쓰지 않은 채 onChange(next)만 통지하므로, 부모가
checked를 갱신해야 시각 상태가 바뀝니다.
function Setting() {
const [on, setOn] = useState(false);
return (
<Switch checked={on} onChange={setOn}>
이메일 알림
</Switch>
);
}
Props#
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
checked | boolean | — | 제어 on/off — 제공하면 제어 모드(내부 상태 무시, 토글은 onChange만 통지) |
defaultChecked | boolean | false | 초기 on/off — 이후 상태는 내부 소유(비제어, checked 미제공 시) |
onChange | (checked: boolean) => void | — | 토글 콜백 — 다음 상태값을 전달 |
size | 'sm' | 'md' | 'md' | 컨트롤 크기 — md 44×24 / sm 36×20 (히트 영역은 둘 다 44px) |
children | ReactNode | — | 라벨 — label로 감싸 클릭 연동 + aria-labelledby 연결 |
…rest | Omit<ButtonHTMLAttributes, 'onChange' | 'children' | …> | — | aria-label · disabled 등은 내부 button으로 전달 |
className은 루트 label에 적용됩니다.
접근성#
button[role="switch"]+aria-checked— 보조기술에 on/off 상태로 보고Space/Enter활성화는 네이티브 button 의미론에 위임 — 별도 키 핸들러 없음children라벨은<label>클릭 연동 +aria-labelledby로 이름 연결 — 라벨 없이 쓰면aria-label을 부여하세요- 썸은 장식(
aria-hidden) — 상태의 진실은aria-checked
토큰#
component 토큰 없이 semantic을 직접 소비합니다(신설 기준 §4 미충족).
| 속성 | 토큰 |
|---|---|
| 트랙 off | color.surface-muted + color.border (hover border-strong) |
| 트랙 on | color.primary |
| 썸 | color.surface + shadow.sm · on 시 color.on-primary |
| 라운드 | radius.full |
| 히트 영역 | control.height-md (44px) |
| 라벨 | font.size-body-1 |
| 비활성 | color.text-placeholder |
| 모션 | duration.fast + ease.standard (썸 이동·트랙 색) |