React 상태 공유

테마 상태 전파 점검

테마 변경은 색상 토글 하나가 아니라 디자인 토큰의 적용 범위 문제입니다. 저장, 시스템 설정, 대비, 하드코딩 색을 함께 확인합니다.

state pipeline

선택값은 하나, 적용 경로는 세 갈래

저장값, 시스템 기본값, 사용자 토글이 Provider에서 한 번만 합쳐진다.

browser prefers-color-scheme 명시 선택이 없을 때만 초기 기본값으로 사용
storage localStorage.theme 사용자가 고른 light/dark/system 값을 복원
event toggle click 버튼은 setTheme만 호출하고 색을 직접 만지지 않음
single source of truth ThemeProvider theme, resolvedTheme, setTheme을 함께 관리한다.
light dark system
hydration 전에는 저장값을 읽고, 렌더 뒤에는 root 속성과 저장소를 같은 방향으로 갱신한다.
root html[data-theme] 문서 루트에서 실제 resolved theme을 노출
tokens CSS variables 배경, 텍스트, 보더, 강조색을 토큰으로만 전달
component button / card / chart 하드코딩 색상은 대비 실패의 원인으로 추적
token proof

테마는 색 이름이 아니라 대비 계약이다

같은 컴포넌트가 light, dark, accent 표면에서 읽히는지 확인한다.

Light surface text / surface / border token
검증 root가 light일 때 저장값과 버튼 상태가 일치
Dark surface contrast remains readable
검증 하드코딩 검정/회색이 섞여 흐려지지 않는지 확인
Accent surface track color is still React cyan
검증 강조색은 트랙 테마를 유지하고 상태색과 구분
regression loop

새로고침부터 대비까지 한 줄로 검증

테마 문제는 상태, 저장, CSS, 접근성 중 한 곳에서 끊긴다.

01 restore 새로고침 후 복원 저장된 선택이 Provider 초기 상태와 root 속성으로 이어지는지 본다.
02 system system fallback 명시 선택이 있을 때 OS 변경이 사용자 선택을 덮지 않게 한다.
03 token CSS 변수 적용 컴포넌트가 root class가 아니라 토큰을 통해 색을 받는지 추적한다.
04 contrast 대비 증거 남기기 텍스트, 보더, 포커스 링이 다크 모드에서도 읽히는지 기록한다.
상태 계약 theme은 사용자의 의도, resolvedTheme은 실제 색상이다.
저장 계약 명시 선택은 저장하고, system은 OS 값을 관찰하되 저장값을 덮지 않는다.
스타일 계약 컴포넌트는 토큰만 읽고, 개별 색상 분기는 Provider 밖으로 새지 않는다.