Setting up Dark Mode for Nuxt and Storybook via Tailwind CSS
Tags: tailwindcss, storybook, nuxt, vue
Published: 2020-12-29 13:30:02

This article reviews configuring dark mode via Tailwind CSS for Nuxt and Storybook. The following resources are used:

- [Nuxt](https://nuxtjs.org/) and [Vue](https://vuejs.org/)
- [Color Mode module](https://color-mode.nuxtjs.org/) for Nuxt
- [Storybook](https://storybook.js.org/) via [Storybook module]() for Nuxt
- [Dark Mode addon](https://github.com/hipstersmoothie/storybook-dark-mode) for Storybook
- [Tailwind CSS](https://tailwindcss.com/) via [Tailwind CSS module](https://tailwindcss.nuxtjs.org/) for Nuxt
- [Dark Mode Plugin](https://github.com/ChanceArthur/tailwindcss-dark-mode) for Tailwind CSS

The [companion repository](https://github.com/visini/nuxt-tailwind-storybook-dark-mode) includes the complete configuration of all moving parts, demonstrated via the example of a simple Button component:

<https://github.com/visini/nuxt-tailwind-storybook-dark-mode>

## Nuxt Color Mode – Enabling Dark Mode

[Color Mode module](https://color-mode.nuxtjs.org/) adds boilerplate-free and effortless color mode switching – including auto detection based on the system's [color-mode](https://drafts.csswg.org/mediaqueries-5/#descdef-media-prefers-color-mode) preferences – to any Nuxt app. See [this excellent walkthrough](https://nuxtjs.org/blog/going-dark-with-nuxtjs-color-mode/) for a more thorough introduction.

![nuxt-tailwind-dark-mode-dark](https://dev-to-uploads.s3.amazonaws.com/i/c4wi00s593gl3qha6jj4.png)
 
Different color modes require different styling. Thus, every component needs to be configured with conditional styling for all supported color modes, which will be applied based on the user's selection.

![nuxt-tailwind-dark-mode-light](https://dev-to-uploads.s3.amazonaws.com/i/od8mtlgglb3f0dyi2nyr.png)

In order to define global styles for dark mode, add the respective CSS declarations. For instance, specify white text on dark background for when dark mode is activated by the user:

```css
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

.dark {
  @apply bg-dark;
  @apply text-white;
}
```

Tailwind CSS utility classes based on props such as the component's `variant` can be dynamically computed within `buttonClass()` – for both light and dark mode. A `base` class provides fundamental styling scoped to the button component via `@apply`.

```vue
<template>
  <button class="base" :class="buttonClass">
    <slot name="text">{{ text }}</slot>
  </button>
</template>

<script>
export default {
  props: {
    variant: {
      type: String,
      default: "primary",
    },
    square: {
      type: Boolean,
      default: false,
    },
    text: {
      type: String,
      default: "Button",
    },
  },
  computed: {
    buttonClass() {
      const c = []
      // Square
      if (!this.square) {
        c.push("rounded-md")
      }
      // Variant
      if (this.variant === "primary") {
        c.push("bg-primary-500 hover:bg-primary-600")
        c.push("dark:bg-primary-900 dark-hover:bg-primary-800")
      } else if (this.variant === "secondary") {
        c.push("bg-gray-500 hover:bg-gray-600")
        c.push("dark:bg-gray-700 dark-hover:bg-gray-600")
      }
      return c.join(" ")
    },
  },
}
</script>

<style lang="postcss" scoped>
.base {
  @apply font-bold py-2 px-4 text-white;
}
</style>
```

## Storybook Dark Mode – Component Library

A third-party [Dark Mode addon](https://github.com/hipstersmoothie/storybook-dark-mode) for Storybook allows switching both UI _and_ component view between light and dark mode. Optional: Add `argTypes` to interact with a component's arguments dynamically via a graphical UI. See Storybook's [control addon docs](https://storybook.js.org/docs/react/essentials/controls) for more information. For instance, switch between rectangular and default (round) buttons by modifying component props via Storybook's UI.

```javascript
import Button from "./Button"

export default {
  title: "Button",
  component: Button,
  argTypes: {
    variant: {
      control: {
        type: "select",
        options: ["primary", "secondary"],
      },
      defaultValue: "primary",
    },
    square: { control: "boolean" },
    text: {
      control: "text",
    },
  },
}

export const Template = (arg, { argTypes }) => ({
  components: { Button },
  props: Object.keys(argTypes),
  template: '<Button v-bind="$props" />',
})

export const Primary = Template.bind({})
Primary.args = {
  variant: "primary",
}

export const Secondary = Template.bind({})
Secondary.args = {
  variant: "secondary",
}

export const Square = Template.bind({})
Square.args = {
  square: true,
}
```

Adding dark mode support directly within Storybook enables effortless display of stories and components in both color modes – in the same way users would switch between modes – i.e., based on CSS class inheritance: A `dark` class is added to [Dark Mode Plugin](https://github.com/ChanceArthur/tailwindcss-dark-mode) for Tailwind CSS to the `<head>` tag, while [Color Mode module](https://color-mode.nuxtjs.org/) for Nuxt adds the `dark` class to the `<html>` tag.

![storybook-dark-mode-dark](https://dev-to-uploads.s3.amazonaws.com/i/cvlw3411dto2pcnvecq4.png)
 
The top right corner of the center toolbar enables switching between light and dark mode. This will switch the UI between color modes, and, as configured in the [companion repository](https://github.com/visini/nuxt-tailwind-storybook-dark-mode), at the same time modify the component view with a specified `dark` class, effectively simulating an user's color mode preference.

![storybook-dark-mode-light](https://dev-to-uploads.s3.amazonaws.com/i/eetendhozbt34mcipkn4.png)
 
## Optional – Tailwind Config Viewer

A useful tool for previewing your Tailwind CSS configuration is [Tailwind Config Viewer](https://github.com/rogden/tailwind-config-viewer), which is integrated into Nuxt's [Tailwind CSS module](https://tailwindcss.nuxtjs.org/) since `v3.4.0`. Simply launch Nuxt in dev mode and access `/_tailwind/` in your browser.

![nuxt-tailwind-config-viewer](https://dev-to-uploads.s3.amazonaws.com/i/hpkzntrld9dje0lhufrw.png)
 
## Conclusion

I hope this article proves insightful to anyone wanting to set up Nuxt with Tailwind CSS and Storybook. As shown here, supporting dark mode for component prototyping and design, and subsequent integration in your frontend app requires some additional tooling. See the [companion repository](https://github.com/visini/nuxt-tailwind-storybook-dark-mode) for specific configuration of all moving parts. Let me know if you have suggestions – I'm curious to learn of alternative approaches!