Setting Up Accessibility Features (Dark Mode) in Next JS (With TailwindCSS)
Tags: nextjs, tailwindcss, typescript, react
Published: 2023-12-06 12:24:48

In my journey to incorporate the dark mode feature into Next.js, I vividly recall my initial attempt using a familiar approach from React—the `useContext` hook. Unfortunately, this method proved unsuccessful, leading me to an extensive exploration marked by numerous hours of trial and error. Despite facing challenges and encountering errors, persistence ultimately paid off as I uncovered the correct path to seamlessly integrate dark mode functionality into Next.js.

In this post, we'll walk through how to implement dark mode in a Next.js application using Tailwind CSS and the next-themes library.

## Setting Up
To commence, ensure you have a Next.js application with Tailwind CSS configured. Fortunately, simplifying this process is the `npx create-next-app@latest` command, which conveniently sets up a Next.js app pre-configured with Tailwind. Execute this command to effortlessly initialize and set up your Next.js application.

## Install `next-themes`
[next-themes](https://www.npmjs.com/package/next-themes) is:
> An abstraction for themes in your Next.js app.

## Implementing Dark Mode
Implementing dark mode in Next.js is effortlessly achieved through the dark variant in Tailwind CSS. Simply prefix properties with dark: to designate them for dark mode. For instance, utilizing dark:text-red-700 adjusts the text color to red-700 when the theme is switched to dark.

By default, Next.js aligns with system preferences for theme selection. Nevertheless, to seamlessly toggle between light and dark modes, configure the darkMode strategy to 'class' in the **tailwind.config.js** file:
`darkMode: "class",`

## Setup your ThemeProvider
`next-themes` needs a ThemeProvider to manage themes in your project. You can either create a special component or wrap your main layout with the `ThemeProvider` component from next-themes to make it work.

Custom Component (Import this into your `layout.tsx` file):
```tsx
"use client";
import * as React from "react";
import { ThemeProvider } from "next-themes";

type Props = {
  children?: React.ReactNode;
};

export function ThemeProvider({children}) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
      {children}
    </ThemeProvider>
  );
}
```

Using the Existing Component in your `layout.tsx` file:
```tsx
import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "My NextJS Web App",
  description: "Setting up Dark Mode in NextJS!",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}
```

## Set up some Global Styles:
Next, let's set up some global styles for things like background color and text appearance when switching modes. We'll handle this in our globals.css file.
```css
@layer base {
  body {
    @apply dark:bg-[#0a0a0a] 
        bg-[#edf6f9];
  }
}
```
Ensuring your application is accessible in both light and dark modes is crucial. When selecting text and background colors, prioritize adequate contrast. You can evaluate your application's accessibility with tools such as the Accessibility Insights browser extension.

## Add your ThemeToggle Component:
Now, we require a component for seamless theme switching. Utilizing the `useTheme` hook enables us to determine the current theme, and incorporating an `onClick` event facilitates state transitions. Initially, we establish our theme to align with the system theme.

```tsx
"use client";
import React from "react";
import { useTheme } from "next-themes";
import { RiMoonLine, RiSunLine } from "react-icons/ri";

const DarkModeToggle = () => {
  const { theme, setTheme } = useTheme();
  return (
    <button
      onClick={() => (theme == "dark" ? setTheme("light") : setTheme("dark"))}>
      {theme === "light" ? (
        <RiMoonLine/>
      ) : (
        <RiSunLine/>
      )}
    </button>
  );
};

export default DarkModeToggle;
```
## What's next
Import the `ThemeToggle` Component into your application, and you're all set! It's essential to note that to fully experience the capabilities of `next-themes`, you'll need to incorporate styles for dark mode by using the `dark:` prefix throughout your entire app. That concludes the setup!