Next.jsとTailwindCSSでダークモードを実装する
タイトルの通りです。Next.jsとTailwindCSSを使用してダークモードを実装してみたので、その備忘録になります。
ライブラリはテーマの切替・管理にnext-themesを使用しました。
まずはライブラリをインストール
npm install next-themes
次に_app.tsx
にnext-themesのprovider
を設置する。
attribute
をclass
にするとルート要素(html
)にdark
クラスが付与される。(デフォルトはdata-theme
属性)
OSの環境設定に基づいてライトとダークを切り替えるようにする場合はenableSystem
をtrue
にする。
import '@/styles/globals.scss';
import type { AppProps } from 'next/app';
import { ThemeProvider } from 'next-themes';
const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<ThemeProvider attribute='class' enableSystem={true}>
<Component {...pageProps} />
</ThemeProvider>
);
};
export default MyApp;
次にtailwind.config.js
にダークモードを利用するように設定する。指定はmedia
とclass
があるが、今回はclass
で切替を行うのでclass
を指定。media
を指定した場合はOSの環境設定に基づいて設定される。
module.exports = {
darkMode: 'class',
...
ひとまずこれでダークモードの適用は完了で、TailwindCSSで指定してあげる場合は接頭辞にdark:
をつける。
import { Html, Head, Main, NextScript } from 'next/document';
const Document = () => {
return (
<Html>
<Head />
<body className='dark:bg-primary-950 dark:text-body-white'> // ダークモード用の記述
<Main />
<NextScript />
</body>
</Html>
);
};
export default Document;
次にダークモード用の切替ボタンを作成する。こちらもライブラリをimport
して現在のtheme
がどちらなのかを判定してボタンを切り替える。
import { useEffect, useState } from 'react';
import { useTheme } from 'next-themes';
import { BsSunFill, BsMoonStarsFill } from 'react-icons/bs';
export const ChangeThemeButton: React.FC = () => {
const { theme, setTheme, resolvedTheme } = useTheme();
const [mounted, setMounted] = useState<boolean>(false);
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (mounted && theme === 'system') {
setTheme(`${resolvedTheme}`);
}
}, [mounted]);
return (
<button
className='rounded-full p-2 transition duration-300 hover:scale-110 hover:bg-secondary-50 dark:hover:bg-secondary-900'
type='button'
aria-label={mounted ? (theme === 'dark' ? 'ダークモード' : 'ライトモード') : 'テーマ切り替え'}
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
{mounted && (
<>{theme === 'dark' ? <BsSunFill size={'18px'} /> : <BsMoonStarsFill size={'1.2rem'} />}</>
)}
</button>
);
};
export default ChangeThemeButton;
初回はtheme
のvalue
がsystem
になるので、そこを初回+theme
がsystem
の場合にresolveTheme
を使用してdark
かlight
モードかを判別して、setTheme
に格納してます。
あとはtheme
の値に合わせて切替を行うみたいな感じです。以上!
参考記事
https://github.com/pacocoursey/next-themes