본문 바로가기

React

React에서 CSS 변수와 JavaScript를 연동해 런타임 테마 커스터마이징 구현하기

React 프로젝트에서 사용자가 실시간으로 테마 색상을 변경하도록 구현하고 싶으신가요? CSS 변수(:root)와 JavaScript를 결합하면 별도의 CSS 파일을 교체하지 않고도 손쉽게 색상을 바꿀 수 있습니다. 이번 글에서는 기본 설정부터 고급 팁까지 단계별로 살펴보겠습니다.

1. CSS 변수 정의하기

먼저 :root에 테마에 사용할 변수를 선언합니다. src/index.css 혹은 전역 스타일 파일에 아래와 같이 작성합니다.

:root {
  --color-primary: #1976d2;
  --color-background: #ffffff;
  --color-text: #212121;
}

body {
  background-color: var(--color-background);
  color: var(--color-text);
}

.button {
  background-color: var(--color-primary);
  color: #fff;
  border: none;
  padding: 0.5rem 1rem;
  cursor: pointer;
}

2. JavaScript로 CSS 변수 업데이트

CSS 변수는 document.documentElement.style.setProperty('--var-name', value) 로 언제든 변경할 수 있습니다. React에서는 이를 훅으로 감싸면 재사용성이 높아집니다.

import { useCallback } from 'react';

export const useTheme = () => {
  const setTheme = useCallback((vars) => {
    const root = document.documentElement;
    Object.entries(vars).forEach(([key, value]) => {
      root.style.setProperty(`--${key}`, value);
    });
  }, []);

  return { setTheme };
};

3. 테마 토글 컴포넌트 만들기

이제 위 훅을 사용해 라이트·다크 테마를 전환하는 UI를 구현합니다.

import React, { useState, useEffect } from 'react';
import { useTheme } from './useTheme';

const lightTheme = {
  'color-primary': '#1976d2',
  'color-background': '#ffffff',
  'color-text': '#212121',
};

const darkTheme = {
  'color-primary': '#90caf9',
  'color-background': '#121212',
  'color-text': '#e0e0e0',
};

export default function ThemeToggle() {
  const { setTheme } = useTheme();
  const [isDark, setIsDark] = useState(false);

  useEffect(() => {
    setTheme(isDark ? darkTheme : lightTheme);
  }, [isDark, setTheme]);

  return (
    
  );
}

4. 사용자가 직접 색상 선택하기

단순 토글이 아니라 사용자가 색상 팔레트를 선택하도록 하면 더욱 유연한 커스터마이징이 가능합니다. input[type="color"]와 useTheme을 결합해보세요.

export default function CustomColorPicker() {
  const { setTheme } = useTheme();
  const [primary, setPrimary] = useState('#1976d2');

  const handleChange = (e) => {
    const newColor = e.target.value;
    setPrimary(newColor);
    setTheme({ 'color-primary': newColor });
  };

  return (
    
); }

5. 로컬스토리지에 테마 상태 저장

페이지를 새로고침해도 사용자가 선택한 테마가 유지되게 하려면 로컬스토리지를 활용합니다.

useEffect(() => {
  const saved = localStorage.getItem('theme');
  if (saved) {
    const vars = JSON.parse(saved);
    setTheme(vars);
    setIsDark(vars['color-background'] === '#121212');
  }
}, []);

useEffect(() => {
  const current = isDark ? darkTheme : lightTheme;
  localStorage.setItem('theme', JSON.stringify(current));
}, [isDark]);

6. 최적화 팁

  • CSS 변수는 transition과 결합하면 부드러운 색상 전환 효과를 줄 수 있습니다. 예: body { transition: background-color 0.3s, color 0.3s; }
  • 대규모 프로젝트에서는 테마 스키마를 typescript 인터페이스로 정의해 타입 안전성을 확보하세요.
  • SSR(Next.js) 환경에서는 useEffect 대신 useLayoutEffect를 사용해 클라이언트와 서버 간 스타일 불일치를 방지합니다.

위 과정을 따라 하면 React 앱에서 CSS 변수와 JavaScript를 활용한 런타임 테마 커스터마이징을 손쉽게 구현할 수 있습니다. 필요에 따라 색상 외에도 폰트, 간격 등 다양한 디자인 토큰을 변수화하면 더욱 풍부한 사용자 맞춤형 UI를 제공할 수 있습니다.