Next.js13でダークモード対応をする
このサイトをダークモード対応してみました🌞🌛
開発環境
- Next.js 13.4.4
- next-themes 0.2.1
手順
パッケージのインストール
next-themesというパッケージを使います。
https://www.npmjs.com/package/next-themes
$ npm install next-themes
プロバイダーの作成
next-themesのThemeProviderは、クライアントコンポーネントでしか動きません。
なので、新規ファイルproviders.tsxをappディレクトリ配下に作ります。
'use client';
import { ThemeProvider } from 'next-themes';
export function Providers({ children }: { children: React.ReactNode }) {
return <ThemeProvider>{children}</ThemeProvider>;
}
ただ、このままではハイドレーションエラーが出てしまいます。
next-themesのGitHubにも以下の記述がありました。
Because we cannot know the theme on the server, many of the values returned from useTheme will be undefined until mounted on the client. This means if you try to render UI based on the current theme before mounting on the client, you will see a hydration mismatch error.
引用元:https://github.com/pacocoursey/next-themes#avoid-hydration-mismatch
つまり、サーバー側の情報とクライアント側の情報が一致していないよという状態ですね。
この対処法についてもGitHubに記載があったの、そちらを参考に以下のように対応しました。
'use client';
import { ReactNode, useEffect, useState } from 'react';
import { ThemeProvider } from 'next-themes';
export function Providers({ children }: { children: ReactNode }) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) return <>{children}</>;
return <ThemeProvider>{children}</ThemeProvider>;
}
ちなみに結構議論されていたみたいです。
https://github.com/pacocoursey/next-themes/issues/152
テーマスイッチャーの作成
実際にテーマを切り替えるためのコンポーネントを作成します。
next-themesのuseTheme
というフックで簡単に切り替えを実装できます。
'use client';
import { useTheme } from 'next-themes';
import { LightModeIcon, DarkModeIcon } from '@/components/ui/icons/index';
export const ThemeChanger = () => {
const { theme, setTheme } = useTheme();
return (
<div>
{theme === 'light' ? (
<button className="sun" onClick={() => setTheme('dark')}>
<DarkModeIcon />
</button>
) : (
<button className="moon" onClick={() => setTheme('light')}>
<LightModeIcon />
</button>
)}
</div>
);
};
ダークモード用のスタイルを書く
テーマの切り替えに応じて、htmlタグの属性が切り替わります。
ライトモードのとき
<html lang="ja" data-theme="light" style="color-scheme: light;">
ダークモードのとき
<html lang="ja" data-theme="dark" style="color-scheme: dark;">
この属性を使ってCSSを書けばOKです。
:root {
--color-bg-main: #fff;
}
[data-theme='dark'] {
--color-bg-main: #333;
}
body {
background-color: var(--color-bg-main);
}
応用
Tailwind CSSと組み合わせて使う場合
Tailwind CSSの設定ファイルに追記します。
/** @type {import('tailwindcss').Config} */
module.exports = {
// other settigns...
darkMode: 'class',
};
これで、以下のようにdark:
で記述した部分がダークモードのときに適応されるようになります💯
<p className="text-gray-500 dark:text-gray-100">text</p>
感想
わたし自身、ダークモードに切り替えたりすることはないのですが、最近は対応しているサイトも多いので実装してみました。
(7月中に2つ記事を投稿する予定が8月になってしまった🥲)
参考サイト
- next-themes GitHub:https://github.com/pacocoursey/next-themes#next-themes--
- next-themes NPM公式:https://www.npmjs.com/package/next-themes
- Tailwind CSS ダークモード対応:https://tailwindcss.com/docs/dark-mode
- ダークモード対応解説動画:https://www.youtube.com/watch?v=optD7ns4ISQ&t=177s
最後まで読んでいただきありがとうございます!
もしよければ「読んだよ!」の代わりに↑の紙飛行機をクリックで飛ばしてください。わたしの元に届きます。
ありがとうございました