dodam dodam logo

B1ND Docs

Themes

DDS 테마 시스템은 라이트/다크 모드를 손쉽게 관리합니다.

Installation

Terminal
$ pnpm add @b1nd/dodam-design-system/themes

Setup

Next.js

  • ThemeSetter 컴포넌트를 <head> 내에 배치하여 깜빡임 없이 초기 테마를 적용합니다.
  • suppressHydrationWarning 속성을 <html> 태그에 추가하여 hydration 경고를 방지합니다.
tsx
// app/layout.tsx
import { ThemeSetter } from "@b1nd/dodam-design-system/next";
import { PropsWithChildren } from "react";
export default function RootLayout({ children }: PropsWithChildren) {
return (
<html lang="ko" suppressHydrationWarning>
<head>
<ThemeSetter />
</head>
<body>{children}</body>
</html>
);
}

Vite + React

  • 아래를 index.html의 head태그 내부 가장 위에 복사/붙혀넣기 해주세요.
html
<head>
<script>
(function () {
try {
const stored = localStorage.getItem("dds-theme");
const system = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
const theme =
stored === "dark" || stored === "light" ? stored : system;
document.documentElement.dataset.theme = theme;
const style = document.createElement("style");
style.textContent =
"*, *::before, *::after { transition: none !important; }";
document.head.appendChild(style);
window.addEventListener("DOMContentLoaded", () => {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
style.remove();
});
});
});
} catch {}
})();
</script>
</head>

API Reference

Theme Type

tsx
type Theme = "light" | "dark";

Functions

FunctionReturnDescription
initTheme()Theme저장된 테마 또는 시스템 테마를 적용하고 반환
getCurrentTheme()Theme | null현재 적용된 테마 반환
applyTheme(theme)void테마를 적용하고 localStorage에 저장
toggleTheme()void라이트/다크 테마 토글
getSystemTheme()Theme시스템 테마 반환
getStoredTheme()Theme | nulllocalStorage에 저장된 테마 반환
resolveInitialTheme()Theme저장된 테마 또는 시스템 테마 반환

Hooks

useTheme

현재 테마를 반환하는 React Hook입니다.

tsx
import { useTheme } from "@b1nd/dodam-design-system/themes";
function Component() {
const theme = useTheme(); // "light" | "dark"
return <div>Current theme: {theme}</div>;
}

Examples

테마 토글 버튼

tsx
"use client";
import { useTheme, toggleTheme } from "@b1nd/dodam-design-system/themes";
import { Sun, Moon } from "lucide-react";
function ThemeToggle() {
const theme = useTheme();
return (
<button onClick={toggleTheme}>
{theme === "light" ? <Moon /> : <Sun />}
</button>
);
}
현재 테마: light

테마별 스타일링

tsx
import { useTheme } from "@b1nd/dodam-design-system/themes";
function ThemedCard() {
const theme = useTheme();
return (
<div
style={{
backgroundColor: theme === "light" ? "#FFFFFF" : "#232424",
color: theme === "light" ? "#0F0F10" : "#F5F5F5",
}}
>
Theme-aware content
</div>
);
}

이 카드는 현재 테마에 따라 색상이 변경됩니다.

특정 테마 적용

tsx
import { applyTheme } from "@b1nd/dodam-design-system/themes";
function ThemeSelector() {
return (
<div>
<button onClick={() => applyTheme("light")}>Light</button>
<button onClick={() => applyTheme("dark")}>Dark</button>
</div>
);
}

How It Works

테마 적용 흐름

  1. 초기화: ThemeSetter 또는 init-theme.iife.js가 localStorage와 시스템 설정을 확인
  2. 적용: document.documentElement.dataset.theme에 테마 값 설정
  3. CSS 변수: [data-theme="dark"] 선택자로 스타일 적용 (data-theme이 없다면 :root 적용)
  4. 저장: 테마 변경 시 localStorage에 저장되어 새로고침 후에도 유지

CSS 변수 구조

css
:root {
--dds-color-text-primary: #0F0F10;
--dds-color-background-default: #F5F5F5;
/* ... */
}
[data-theme="dark"] {
--dds-color-text-primary: #F5F5F5;
--dds-color-background-default: #191A1A;
/* ... */
}

Flash 방지

Next.js에서 ThemeSetter<head> 내부에서 동기적으로 실행되어 hydration 전에 테마를 적용합니다. 이로 인해 페이지 로드 시 깜빡임(flash)이 발생하지 않습니다.

tsx
// ThemeSetter가 생성하는 스크립트
(function() {
try {
var s = localStorage.getItem("dds-theme");
var m = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
var t = s === "dark" || s === "light" ? s : m;
document.documentElement.dataset.theme = t;
} catch(e) {}
})();