기본적으로 next 13버전에서 tailwind가 설치가 되어있다는 가정(13.2버전 이후)

npm i next-themes react-icons
Next.js에서 쉽게 테마를 전환할 수 있도록 도와주는 패키지입니다.(시스템 테마로도 업데이트 가능)
src
├── Providers.tsx
└── layout.tsx
└── components
└── Elements
└── DarkMode
└── DarkMode.tsx
next 13으로 폴더구조는 위와 같습니다.
"use client";
import { ThemeProvider } from "next-themes";
const Providers = ({ children }: { children: React.ReactNode }) => {
return <ThemeProvider attribute="class">{children}</ThemeProvider>;
};
export default Providers
Providers.tsx는 테마 provider입니다.
위를 통해서 해당 children은 일관된 테마를 유지할수있습니다.
해당 프로젝트에는 layout에서 body안에 적용을 시킬예정입니다.
여기서 핵심은 "use client"를 넣어줘야합니다.
csr로 작동을 해야 ThemeProvider가 작동을 합니다.
👉 이때 attribute="class"를 추가해줌으로써 className에 dark와 light가 토글이 됩니다.
import "./globals.css";
import { Inter } from "next/font/google";
import Header from "./components/Headers/Header";
import Providers from "./Providers";
const inter = Inter({ subsets: ["latin"] });
export const metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={`transition duration-300 ${inter.className}`}>
<body className="flex flex-col min-h-screen">
<Providers>
<Header />
<main className="bg-white dark: bg-black">
{children}
</main>
</Providers>
</body>
</html>
);
}
다음은 layout.tsx파일입니다.- (참고블로그)[https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts]
이 파일은 next에서 해당 공통적으로 들어가는 요소들을 추가하는 파일입니다.
이전 버전으로 예시를 들면 _app.tsx / _document.tsx 가 있습니다.
여기서 핵심은 아래 코드부분입니다.
<Providers>
<Header />
<main className="bg-white dark: bg-black">
{children}
</main>
</Providers>
이전에 Providers.tsx에서 만든 컴포넌트를 불러와서
테마를 적용시킬 범위까지 감싸줍니다.
현 프로젝트는 tailwind이기때문에 이후 main처럼 className에 dark모드 부분에서 사용될 부분에만
위 코드처럼넣어줍니다.
"use client";
import { BsFillSunFill, BsFillMoonFill } from "react-icons/bs";
import { useState, useEffect } from "react";
import { useTheme } from "next-themes";
interface IDarkMode {}
function DarkMode({}: IDarkMode) {
const [mounted, setMounted] = useState(false);
const { systemTheme, theme, setTheme } = useTheme();
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
const onClick = (mode: string) => () => {
setTheme(mode);
};
const currentTheme = theme === "system" ? systemTheme : theme;
return (
<div className="bg-darkModeBg cursor-pointer rounded-[50%] p-1">
{currentTheme === "dark" ? (
<BsFillMoonFill onClick={onClick("light")} />
) : (
<BsFillSunFill onClick={onClick("dark")} />
)}
</div>
);
}
export default DarkMode;
핵심의 페이지 darkMode 버튼입니다.
마찬가지로 click이베트를 사용하기때문에 "use client"를 써줌으로 csr로 진행이 됩니다.
<div className="bg-darkModeBg cursor-pointer rounded-[50%] p-1">
{currentTheme === "dark" ? (
<BsFillMoonFill onClick={onClick("light")} />
) : (
<BsFillSunFill onClick={onClick("dark")} />
)}
</div>
추가적으로 아이콘을 통해서 다크모드와 라이트모드의 구별을 위해서 react-icons를 불러와서 jsx에 넣어줍니다.
이때 div에서 클래스네임중에 bg-darkModeBg은 무엇인가??
이거는 tailwind에서 사용자 설정을 해준 class입니다.
아래 tailwind설정에 보면 colors 안에 key값이 있습니다.
클래스안에 dark:를 써줘서 관리를 하는 방법이있고
위처럼 tailwind의 설정을 통해 css로 관리를 하는 방법 총 2가지 방법이있습니다.
더 좋은방법이 있다면 댓글 부탁드리겠습니다ㅎㅎ..
((공식 홈페이지))[https://github.com/pacocoursey/next-themes#readme]
위 useEffect 등 함수적인 부분은 next-Theme에 나와있는 내용을 그대로 카피한 부분이기때문에
따라만 해주신다면 문제가 없습니다.
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
theme: {
extend: {
colors: {
darkModeBg: "var(--hello)",
},
}
}
...
};
위에서 말한 tailwind class 설정방법입니다.
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
--hello: #aea;
}
:root.dark {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
--hello: #e5e5;
}
root.dark는 html에 class가 dark하고 light가 토글되어 나타납니다.
darkMode냐 lightMode냐에 따라서
root color를 통해서 tailwind 설정에서 var(--hello)를 통해 해당 칼라값을 찾아가고
그 해당값을 통해서 요소의 색상이 결정됩니다.
모든것은 공식문서에 나타나있지만 아직은 서투르고 어려운 부분이 있다..!
어렵더라도 꾸준히 공식문서들을 활용하고 요령을 익히는 방법을 터득해보자!