Adding a Dark Theme to Next.js with Stitches
Tags: nextjs, typescript, css
Published: 2022-03-14 02:59:48

If you enjoy writing performant CSS with `styled-components` and need type-safety from Typescript when interfacing with design tokens then Stitches might be the solution right up your alley. 

[Stitches](https://stitches.dev/) is a CSS-in-JS library that provides awesome DX and support for SSR frameworks like Next.js out of the box. In this tutorial, we will use Stitches to add a basic dark theme to a Next.js app with Typescript.

## Initial Setup

Setting up Stitches with Next.js is easy and it works even better with the Typescript example from Vercel.

```bash
yarn create next-app --typescript nextjs-stitches-dark-theme

//then followed by
yarn add @stitches/react
```

Now we can create a config file that will export all of our API functions from the library, this can be created anywhere in your project, such as the root.

```ts
// stitches.config.ts
import { createStitches } from "@stitches/react";

export const { 
  styled, 
  getCssText, 
  createTheme, 
  globalCss 
} = createStitches({ 
  theme: {
    /* ... other tokens */
    colors: {
      text: "black",
      background: "white",
    }
  }
 });

// define the dark theme using the de-constructed function
export const darkTheme = createTheme({ 
  colors: { 
    text: "white",
    background: "black"
  } 
});
```

For a basic dark theme, we would want to use these theme tokens at a global level in the CSS specification, so we can use the `globalCss` function in the same config file to declare these styles.

```typescript
// stitches.config.ts

/* ...previous code */

const GlobalStyles = globalCss({
  body: {
    //we can call the color token values with the
    //$ prefix in a string
    background: "$background", 
    color: "$text"
  }
})

//we can declare the styles here or in pages/_app.tsx
GlobalStyles();
``` 
While that is all for configuring Stitches, you might be wondering where is the `ThemeProvider` that most CSS-in-JS libraries like `emotion` or `styled-components` provides. Actually, a basic installation of Stitches does not need it, you can start using the `styled` function by exporting it from this config file and start styling components.

## Creating a Theme Toggle

But for managing multiple themes, it is highly recommended to install an additional packaged called [next-themes](https://github.com/pacocoursey/next-themes) which will allow us to toggle between themes and override the theme-specific tokens, such as colours in this case.

```console
yarn install next-themes
```

After adding the package, we can add the familiar theme provider component into our Next.js application.

```tsx
// pages/_app.tsx
import type { AppProps } from "next/app";
import { ThemeProvider } from "next-themes";
import { darkTheme } from "../stitches.config";

export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider
      attribute="class"
      defaultTheme="system"
      value={{
        light: "light",
        dark: darkTheme.className
      }}
    >
      <Component {...pageProps} />
    </ThemeProvider>
  );
}
```

And now we can create a toggle button to switch between the themes with the `useTheme` hook from `next-themes`;

```tsx
// pages/index.tsx
import { styled } from "../stitches.config";
import { useTheme } from "next-themes";

const Button = styled("button", {});

export default function IndexPage() {
  const { theme, setTheme } = useTheme();
  const toggleTheme = () =>
    setTheme(theme === "light" ? "dark" : "light");

  return (
    <div>
      <h1>The current theme is {theme === "dark" ? "dark" : "light"}</h1>
      <Button onClick={toggleTheme}>Change Theme</Button>
    </div>
  );
}
```

And that is pretty much everything we need to have a dark mode theme with Stitches! 🎉

## Additional Notes

Theming with Stitches, especially with a dark theme, requires a bit of forethought into the selection of the colour tokens since we would need to define our palettes with the same key name i.e. `text` is the same colour token key, but has a different value in the light and dark theme.

Luckily, the wonderful folks over at Modulz also provide a variety of colour palettes to choose from through their [Radix-UI/colors](https://www.radix-ui.com/colors) package.

If this tutorial with Stitches suits your theming needs, then feel free to check out the full Codesandbox below:

{% codesandbox stitches-dark-mode-zrbqqg %}

Happy theming! ✨