Next.js와 Tailwind CSS를 같이 사용하는 프로젝트가 상당히 많습니다.
create-next-app 명령어를 실행하면 Next.js 설치 과정에서 Tailwind CSS를 사용하는지 물어볼 정도 입니다.
이번 글에서는 next-theme을 라이브러리를 활용한 다크 모드 적용에 대해서 글을 써보려 합니다.
작업 환경 설정
npx create-next-app@latest my-project --typescript --eslint
cd my-project
yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
// Or if using `src` directory:
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {},
},
plugins: [],
}
// styles/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
간단한 Next.js와 Tailwind CSS 환경을 세팅해보았습니다. 자세한 사항은 공식문서에서 확인 하실수 있습니다.
yarn add next-themes react-icons
next-themes는 _app.tsx에 Redux나 Styled-Component와 비슷하게 다크 모드에 대한 Provider를 제공하기 위해서 사용하는 라이브러리입니다.
react-icons는 다양한 아이콘을 컴포넌트 하나만 불러와서 간단하게 사용하게 해주는 라이브러리입니다. 이번 글에서는 다크모드 버튼의 아이콘을 위해 사용합니다.
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {},
},
plugins: [],
darkMode: "class", // <-- dark 클래스가 앞에 있으면 다크 테마를 적용시켜주고, 없다면 기본 테마를 적용시켜줍니다.
};
tailwind.config.js 파일에서 darkMode 설정을 해주었습니다.
컴포넌트 작성
import "@/styles/globals.css";
import { ThemeProvider } from "next-themes";
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
return (
<ThemeProvider enableSystem={true} attribute="class">
<Component {...pageProps} />
</ThemeProvider>
);
}
ThemeProvider에서 enableSystem은 저희의 데스크탑이나 모바일 환경의 다크 모드 설정을 따라갑니다.
// Logo.tsx
import Link from "next/link";
const Logo = () => {
return (
<Link href="/" className="my-2 flex items-center space-x-1">
<span className="font-bold text-3xl font-sans tracking-tight whitespace-nowrap">
다크 모드
</span>
</Link>
);
};
export default Logo;
Logo 컴포넌트는 저희가 다크 모드가 적용됐는지 텍스트로 확인하기 위해 작성하였습니다.
// SwitchMode.tsx
import React, { useState, useEffect } from "react";
import { useTheme } from "next-themes";
import { FiSun, FiMoon } from "react-icons/fi";
const SwitchMode = () => {
const { systemTheme, theme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
const renderThemeChanger = () => {
if (!mounted) {
return null;
}
const currentTheme = theme === "system" ? systemTheme : theme;
if (currentTheme === "dark") {
return (
<FiSun
className="w-10 h-10 text-white-500 "
role="button"
onClick={() => setTheme("light")}
/>
);
} else {
return (
<FiMoon
className="w-10 h-10 text-gray-900 "
role="button"
onClick={() => setTheme("dark")}
/>
);
}
};
return <div>{renderThemeChanger()}</div>;
};
export default SwitchMode;
useTheme의 systemTheme은 현재 유저가 사용하고 있는 기기의 테마 설정입니다.
renderThemeChanger 함수는 다크 모드, 일반 모드 아이콘을 현재 다크 모드 여부에 따라 렌더링 해줍니다.
currentTheme은 시스템 테마 설정을 그대로 가져오며, theme 시스템 테마 설정이 없으면, 유저가 웹 앱 내에서 사용한 theme을 사용합니다.
mounted State와 useEffect는 hydration mismatch를 피하기 위해 사용됩니다.
서버에서는 theme을 알 수가 없기 때문에 useTheme이 클라이언트에서 마운트 될 때까지 undefined가 됩니다.
이를 방지하기 위해 서버가 아닌 클라이언트가 마운트 됐을 때 밑의 아이콘들을 렌더링 하도록 하였습니다.
이제 다크 모드가 제대로 바뀌는지 확인하기 위한 설정을 해보겠습니다.
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base{
body {
@apply bg-gray-50 text-gray-900 dark:bg-black dark:text-gray-100;
}
}
// Header.tsx
import * as React from "react";
import Logo from "./Logo";
import SwitchMode from "./SwitchMode";
const Header = () => {
return (
<header className="h-15">
<div className="container px-4 sm:px-6 py-4 flex justify-between items-center">
<Logo />
<SwitchMode />
</div>
</header>
);
};
export default Header;
다크 모드가 적용된 것을 확인하실 수 있습니다!
Reference
https://nextjsdev.com/add-dark-mode-in-nextjs-app-using-tailwind-css-dark-mode?x-host=nextjsdev.com
Add Dark mode in Nextjs App using Tailwind CSS Dark Mode.
Today, we are going to discuss how we can add dark mode in Next.js App using Tailwind CSS dark mode in just 5 easy steps.
nextjsdev.com
'Development > React' 카테고리의 다른 글
Storybook 7.0을 통한 프로젝트 문서화와 테스팅 (0) | 2023.04.13 |
---|---|
Styled Components ttf 폰트 적용 문제 해결 (0) | 2023.01.30 |
React Query 테스팅하기(@tanstack/react-query) (0) | 2023.01.16 |
Next.js) msw로 백엔드 Mocking 해보기 (0) | 2023.01.12 |
Next.js)@testing-library로 컴포넌트 테스팅하기 (0) | 2023.01.11 |