Implémenter le dark mode avec Tailwindcss dans Next.js

La version 2.0 de tailwindcss apporte plusieurs nouveautés, notamment le support de dark mode rendant plus facile que jamais la modification dynamique de votre application lorsque le mode sombre est activé.

Nous allons commencer par créer une nouvelle application Next.js

npx create-next-app dark-mode

Installation de tailwindcss

yarn add -D tailwindcss postcss postcss-preset-env

et next-themes qui va nous permettre de basculer en dark mode

yarn add next-themes

Créer un fichier postcss.config.js et collez la configuration ci-dessous de postcss

module.exports = {
plugins: [
"tailwindcss",
[
"postcss-preset-env",
{
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
features: {
"custom-properties": false,
},
},
],
],
};

Ensuite créer un fichier tailwindcss.config.js et ajouter la configuration ci-dessous

module.exports = {
future: {
removeDeprecatedGapUtilities: true,
purgeLayersByDefault: true,
},
darkMode: "class",
purge: ["./components/**/*.{js,ts,jsx,tsx}", "./pages/**/*.{js,ts,jsx,tsx}"],
theme: {},
variants: {},
};

Dans cette configuration, le changement de thème se fera avec les classes, ce qui facilitera intégration avec next-themes.

Dans le répertoire pages, créez un nouveau fichier _document.js et ajoutez la configuration ci-dessous

import React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";

class MyDocument extends Document {
render() {
return (
<Html>
<Head />
<body className="bg-white text-black dark:bg-black dark:text-white">
<Main />
<NextScript />
</body>
</Html>
);
}
}

export default MyDocument;

Au niveau du body, nous définissions la configuration globale. Lorsque le thème sera par défaut, la couleur des textes sera noire et la couleur de l’arrière plan blanche. Lorsque le dark mode sera déclenché, la couleur des texte sera blanche et la couleur de l’arrière plan noire. vous pouvez les modifier comme bon vous semble.

Dans le répertoire styles, remplacez le contenu de global.css par celui-ci

@tailwind components;
@tailwind utilities;

Ensuite dans le fichier _app.js dans le répertoire pages, nous allons importer ThemeProvider de next-themes et nous allons aussi importer le style global que nous avons définis dans global.css dans le répertoire styles

import "../styles/globals.css";
import { ThemeProvider } from "next-themes";

function MyApp({ Component, pageProps }) {
return (
<ThemeProvider attribute="class">
<Component {...pageProps} />
</ThemeProvider>
);
}

export default MyApp;

Dans le fichier index.js remplacez le contenu initial par celui-ci

import Head from "next/head";

export default function Home() {
return (
<div className="text-center">
<Head>
<title>Dark mode with Tailwind and Next.js</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<h1 className="text:2xl">Dark mode with Tailwind and Next-themes</h1>
</div>
);
}

ensuite lancez le serveur avec

yarn dev

Pour basculer au dark mode nous aurons besoin de useTheme() qui sera importé de next-themes. useTheme() contient plusieurs propriétés mais ce qui va nous intéresser c’est theme, qui renvoie le thème actif et setTheme qui permet de changer de thème.

L’avantage de cette librairie est qu’il permet d’éviter le flash lors du chargement de la page coté serveur car ThemeProvider injecte automatiquement un script dans next/head pour mettre à jour l’élément html avec les attributs corrects avant le chargement du reste de la page. Cela signifie que la page ne clignotera en aucun cas.

nous allons importer useTheme dans index.js

import { useTheme } from "next-themes";

et nous allons extraire theme et setTheme

const { theme, setTheme } = useTheme();

Comme nous allons changer le thème coté client, nous allons vérifier d’abord si le composant est monté. nous allons définir un state avec useState

const [isMounted, setIsMounted] = useState(false);

et nous allons mettre isMounted à true lorsque le composant sera monté

useEffect(() => {
setIsMounted(true);
}, []);

ensuite nous allons définir une fonction qui va permettre de changer le theme, en vérifiant d’abord si le composant est bien monté

const switchTheme = () => {
if (isMounted) {
setTheme(theme === "light" ? "dark" : "light");
}
};

le code complet d’index.js

import { useEffect, useState } from "react";
import Head from "next/head";
import { useTheme } from "next-themes";
export default function Home() {
const [isMounted, setIsMounted] = useState(false);
const { theme, setTheme } = useTheme();
useEffect(() => {
setIsMounted(true);
}, []);
const switchTheme = () => {
if (isMounted) {
setTheme(theme === "light" ? "dark" : "light");
}
};
return (
<div className="text-center">
<Head>
<title>
Dark mode with Tailwind and Next.js
</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<h1 className="text:2xl">
Dark mode with Tailwind and Next- themes
</h1>
<button onClick={switchTheme}>Change theme</button>
</div>
);
}

Vous pouvez actualiser la page et vous ne verrez aucun flash.

Sachez que vous pouvez aussi implémenter le dark mode sans tailwindcss, juste avec la librairie next-themes . elle peut être implémenté avec styled-components, emotion ou avec des classes css

Demo

Code source

React and Node.js developper living in Tunisia

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store