Hey there, In today's article I am going to show you how to add Dark mode to your Next.js application using Tailwind CSS.
What is Next.js?
Next.js is a React based open-source frontend framework, with features like SSR (Server Side Rendering) and SSG (Static Site Generation). Next.js also comes SEO optimized right out the box so you don't have to do it yourself from the scratch.
What is Tailwind CSS?
Tailwind CSS is utility-first CSS framework for quickly building highly customizable User Interfaces with low level CSS, This is great because it provides you an easy way to implement your web design and it only ships the CSS that is being used on the webpage which makes the whole app more light and efficient.
Here is how you can add Dark mode to your Next.js application using Tailwind CSS.
Prerequisites:
Make sure you have Nodejs installed on your local machine.
1. Setting up a new Next.js project
You can skip this step if you already have one.
Run npx create-next-app nextjs-tailwind
in your terminal that should give you a new Next.js project with following files, You can use what ever name you prefer instead of nextjs-tailwind
.
Run cd nextjs-tailwind
to change directory and run npm run dev
or yarn dev
if you are using yarn to start your local developement server.
Go to http://localhost:3000, There you will be able to see the following default Next.js homepage.
2. Adding Tailwind CSS
Run
npm install -D tailwindcss postcss autoprefixer
, It will install Tailwind CSS and all the necessary dependencies.Then run
npx tailwindcss init -p
, It will createtailwind.config.js
andpostcss.config.js
files.-
Open
tailwind.config.js
and do the following code changes.
module.exports = { content: [ "./pages/**/*.{js,ts,jsx,tsx}", "./src/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [], }
It will let Tailwind CSS know that on which files or folders it should be applied. -
Now open
styles/globals.css
and add the following tailwind directives.
@tailwind base; @tailwind components; @tailwind utilities;
Spin up you development server by running
npm run dev
.-
Make following changes into your
pages/index.js
to see if Tailwind CSS is working.
export default function Home() { return ( <div className="pt-6 mt-28"> <div className="flex justify-center items-center flex-col "> <div className="max-w-sm bg-white rounded-lg border border-gray-200 shadow-md mt-10"> <a href="#"> <img className="rounded-t-lg " src="https://source.unsplash.com/random/1920x1080/?laptop" alt="" /> </a> <div className="p-5"> <a href="#"> <h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900"> Laptops that you can't afford even in 2022. </h5> </a> <p className="mb-3 font-normal text-gray-700"> Lorem ipsum dolor sit amet. Cum laudantium laborum ut saepe facilis aut rerum corporis qui debitis voluptas. Rerum dolores aut voluptas galisum aut iure repellendus. </p> <a href="#" className="inline-flex items-center py-2 px-3 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300" > Read more <svg className="ml-2 -mr-1 w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" > <path fillRule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clipRule="evenodd" ></path> </svg> </a> </div> </div> </div> </div> ); }
After this you should be able see a card with a image and some text.
If you are using VS CODE you can use Tailwind CSS IntelliSense for better development experience.
3. Adding Dark mode
To add dark mode we need to install few things.
next-themes
, This package provides an easy to implement themes in Next.js, You can check more on that here.This package is optional you can use text or SVGs directly if you want but I will install
@heroicons/react
, It is an icon library which I will be using to make a theme toggle button.
Run the following command to install above packages.
npm install @heroicons/react next-themes
Edit _app.js
Wrap the whole app with the ThemeProvider
to use next-themes
.
import '../styles/globals.css';
import { ThemeProvider } from 'next-themes';
function MyApp({ Component, pageProps }) {
return (
<ThemeProvider enableSystem={true} attribute="class">
<Component {...pageProps} />
</ThemeProvider>
);
}
export default MyApp;
Then go to tailwind.config.js
and add darkMode: 'class'
after content array.
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./src/**/*.{js,ts,jsx,tsx}',
],
darkMode: 'class',
theme: {
extend: {},
},
plugins: [],
};
Note:
Technically you can hard code
darkMode
intailwind.config.js
and in the attribute of theThemeProvider
but since we want it to have state so I am using class. It will update HTML head and tailwind with the current theme using the ThemeProvider's context.
4. Creating the theme toggle component.
Create a src
folder in root directory of the project and inside that create a file with name ThemeToggler.js
, Add following code.
import { useTheme } from 'next-themes';
import { useState, useEffect } from 'react';
import { MoonIcon, SunIcon } from '@heroicons/react/outline';
const ThemeToggler = () => {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return (
<button
className="w-8 h-8 bg-blue-100 rounded-lg dark:bg-slate-800 flex items-center justify-center hover:ring-2 ring-blue-400 transition-all duration-300 focus:outline-none"
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
aria-label="Toggle Dark Mode"
>
{theme === 'light' ? (
<MoonIcon className="text-blue-500 w-5 h-5" />
) : (
<SunIcon className="text-blue-400 w-5 h-5" />
)}
</button>
);
};
export default ThemeToggler;
Let me break it down for you
I am using
useTheme
hook fromnext-themes
that provides two things, one istheme
which is just a string representing current theme andsetTheme
which is a method to change the current theme. It is similar touseState
hook.Since our component gets rendered on server first so we have some hydration mismatch problem, so in order to solve that I am checking if the component is mounted on the client side using React's
useEffect
hook.In last I am using sun and moon icon to indicate actions with a simple JSX ternary operator.
How to add tailwind utility classes for dark mode.
So the way tailwind CSS dark mode works is similar to hover feature, once you have decided how you want the element to look in dark mode you can just add dark:
in front of any utility classes that you wish to be activated in dark mode only.
Example:
<p className="text-slate-800 dark:text-slate-300"
>
This is some text.
</p>
so text color will be slate-800 if in light mode and slate-300 if it is in dark mode.
Final steps
Now lets add ThemeToggler
and some classes for dark mode in our homepage, Open pages/index.js
and add following code.
import ThemeToggler from '../src/ThemeToggler';
export default function Home() {
return (
<div className="pt-6 mt-28">
<div className="flex justify-center items-center flex-col ">
<ThemeToggler />
<div className="max-w-sm bg-white rounded-lg border border-gray-200 shadow-md dark:bg-gray-800 dark:border-gray-700 mt-10 transition duration-300">
<a href="#">
<img
className="rounded-t-lg "
src="https://source.unsplash.com/random/1920x1080/?laptop"
alt=""
/>
</a>
<div className="p-5">
<a href="#">
<h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
Laptops that you can't afford even in 2022.
</h5>
</a>
<p className="mb-3 font-normal text-gray-700 dark:text-gray-400">
Lorem ipsum dolor sit amet. Cum laudantium laborum ut saepe
facilis aut rerum corporis qui debitis voluptas. Rerum dolores aut
voluptas galisum aut iure repellendus.
</p>
<a
href="#"
className="inline-flex items-center py-2 px-3 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
>
Read more
<svg
className="ml-2 -mr-1 w-4 h-4"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z"
clipRule="evenodd"
></path>
</svg>
</a>
</div>
</div>
</div>
</div>
);
}
If you have done every thing as mentioned you should be able to see something like below on the homepage.
The image can be random because I am using Unsplash API.
Also if you open browser's dev tools, You will be able to see the current state of theme on your local storage.
Thanks for reading, I hope you got something out of it, if you have any questions or suggestions, please feel free to comment below also don't forget to follow me on twitter.
Top comments (1)
Thanks for this great post!