ComponentsP3 본문

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 설정

대신 Checkbox

제출 전까지 보류되는 선택 또는 혼합(indeterminate) 상태가 필요할 때

플레이그라운드#

컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

import { Switch } from '@wds/ui-web';

<Switch>다크 모드</Switch>

해부#

트랙·썸·히트 영역 위에 토큰 실측을 핀으로 얹습니다 — 썸은 장식, 진실은 aria-checked입니다.

md · 44×24px 트랙 + 18px 썸 — 토큰 실측 핀(좌측 높이 브래킷 = 트랙)
track
44 × 24px
thumb
18px
thumb travel
20px
radius
fullradius.full
border
1pxborder-strong
gap
8pxspace-2
label
16pxbody-1
hit area
44pxcontrol.height-md

변형#

라벨 없는 스위치 — aria-label 필수

라벨이 없으면 aria-labelledby 연결도 생략되므로 aria-label을 직접 부여해야 합니다.

크기#

size로 2단(ADR-012 B-P2) — md(기본) 44×24px 트랙 + 18px 썸, sm 36×20px 트랙

  • 14px 썸. 두 크기 모두 시각 트랙과 무관하게 히트 영역이 control.height-md(44px)로 확장되어 터치 타깃을 보장합니다.
md · sm — 트랙·썸 크기차 (히트 영역은 둘 다 44px)
sizetrackthumbtravelhit areamd44 × 24px18px20px44pxsm36 × 20px14px16px44px

상태#

Default · Checked · Disabled
  • Checked — 트랙이 color.primary로 채워지고 썸이 우측으로 이동
  • Focus — 트랙 :focus-visible에 2px primary 아웃라인
  • Disabledcolor.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타입기본값설명
checkedboolean제어 on/off — 제공하면 제어 모드(내부 상태 무시, 토글은 onChange만 통지)
defaultCheckedbooleanfalse초기 on/off — 이후 상태는 내부 소유(비제어, checked 미제공 시)
onChange(checked: boolean) => void토글 콜백 — 다음 상태값을 전달
size'sm' | 'md''md'컨트롤 크기 — md 44×24 / sm 36×20 (히트 영역은 둘 다 44px)
childrenReactNode라벨 — label로 감싸 클릭 연동 + aria-labelledby 연결
…restOmit<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 미충족).

속성토큰
트랙 offcolor.surface-muted + color.border (hover border-strong)
트랙 oncolor.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 (썸 이동·트랙 색)