How I built the dark mode of tailwindcss.com (website + docs) in 10 minutes using Nightwind & Next.js
Tags: javascript, css, tailwindcss, programming
Published: 2021-02-16 20:39:05

Nightwind is a plugin for Tailwindcss that automatically generates the dark mode of any Tailwind website, while also giving full customisation options.

{% github jjranalli/nightwind no-readme %}

From now on, I'll be creating the dark mode of well-known Tailwind websites to explore how Nightwind behaves in different cases. Especially, the effectiveness of its automatic dark mode.

> What Nightwind does is essentially invert the color classes used throughout a website (for example, a bg-red-300 turns into bg-red-600). Thanks to the curated Tailwind color palette, this usually results in a good-looking, coherent dark mode.

{% twitter 1361678659833237509 %}

I picked tailwindcss.com as the first one, as I felt it would've been the most challenging given the complexity and extensive use of color classes throughout the websites.

![Tailwindcss.com homepage dark-mode comparison](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/myldbdkyrg5xercdtz4t.png)

![Tailwindcss.com documentation dark-mode comparison](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnnv17zdpw4kelxc5x48.png)

You can check the dark version of the homepage and the whole documentation here -> **https://night-tailwindcss.vercel.app** (press the Nightwind toggle in the navbar)

---

# How I did it

### 1. Set up Nightwind in next.js, using 'next-themes'

I use ThemeProvider to manage light and dark modes, setting the storageKey parameter to 'nightwind-mode' to make sure the chosen mode persists.
```jsx
// _app.js
import { ThemeProvider } from "next-themes"

function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider
      attribute="class"
      storageKey="nightwind-mode"
      defaultTheme="system" // default "light"
    >
      <Component {...pageProps} />
    </ThemeProvider>
  )
}

export default MyApp
```

In _document.js I simply add the "nightwind" class to the Html element, which is used by Nightwind to manage transitions between modes.
```jsx
// _document.js
import Document, { Html, Head, Main, NextScript } from "next/document"

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }

  render() {
    return (
      <Html className="nightwind">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument
```

### 2. Set up a toggle
```jsx
import { useTheme } from "next-themes"

export default function Toggle() {
  const { theme, setTheme } = useTheme()

  const toggle = () => {
    if (!document.documentElement.classList.contains("dark")) {
      setTheme("dark")
    } else {
      setTheme("light")
    }
  }

  return <button onClick={toggle}>Toggle</button>
}
```

### 3. Add Nightwind into Tailwind.config.js

Finally, I specify what colorClasses and variants I want Nightwind to invert, as well as add the "typography: true" option to invert all colors used by the typography plugin (used in the tailwind documentation).
```jsx
module.exports = {
  darkMode: "class",
  theme: {
     nightwind: {
       typography: true,
       colorClasses: ['gradient', 'ring', 'ring-offset', 'divide', 'placeholder'],
     },
  variants: {
    nightwind: ['group-hover', 'active', 'focus'],
  },
  plugins: [require("nightwind")],
}
```

> Note: There are also some minor modifications that were made to make everything work seamlessly. You can explore the [full commit here](https://github.com/jjranalli/nightwind-demo/commit/00d6f1fd9eec69fe70fc7bcedc2846694c4cc849)

---

To learn more about Nightwind, I suggest you visit:
- [nightwindcss.com demo website](https://nightwindcss.com)
- [My recent post on Nightwind](https://jacoporanalli.com/blog/nightwind)

Thanks for reading! And if you have any suggestion about what other Tailwind website I should create the dark mode for, please let me know! :)