Documentation

Dark and Light mode with auto detection made easy with NuxtJS 🌗

Features

  • Add .${color}-mode class to <html> for easy CSS theming
  • Force a page to a specific color mode (perfect for incremental development)
  • Works with any NuxtJS target (static or server) and rendering (universal and spa)
  • Auto detect the system color-mode
  • Sync dark mode across tabs and windows 🔄
  • Supports IE9+ 👴

Live demo

Nuxt color mode demo

Checkout the online demo.

Setup

Add @nuxtjs/color-mode dependency to your project:

yarn add --dev @nuxtjs/color-mode
npm install --save-dev @nuxtjs/color-mode

Then, add @nuxtjs/color-mode to the buildModules section of your nuxt.config.js

nuxt.config.js
{
  buildModules: [
    '@nuxtjs/color-mode'
  ]
}

Use the modules property instead of buildModules if:

  • you are using ssr: false and nuxt start, see #25
  • you are using nuxt < 2.9.0

You are ready to start theming your CSS with .dark-mode and .light-mode classes ✨

TypeScript

Add the types to your "types" array in tsconfig.json

tsconfig.json
{
  "compilerOptions": {
    "types": [
      "@nuxt/types",
      "@nuxtjs/color-mode"
    ]
  }
}

Usage

It injects $colorMode helper with:

  • preference: Actual color-mode selected (can be 'system'), update it to change the user preferred color mode
  • value: Useful to know what color mode has been detected when $colorMode === 'system', you should not update it
  • unknown: Useful to know if during SSR or Generate, we need to render a placeholder
  • forced: Useful to know if the current color mode is forced by the current page (useful to hide the color picker)
<template>
  <div>
    <h1>Color mode: {{ $colorMode.value }}</h1>
    <select v-model="$colorMode.preference">
      <option value="system">System</option>
      <option value="light">Light</option>
      <option value="dark">Dark</option>
      <option value="sepia">Sepia</option>
    </select>
  </div>
</template>

<style>
body {
  background-color: #fff;
  color: rgba(0,0,0,0.8);
}
.dark-mode body {
  background-color: #091a28;
  color: #ebf4f1;
}
.sepia-mode body {
  background-color: #f1e7d0;
  color: #433422;
}
</style>

Force a color mode

You can force the color mode at the page level (only parent) by setting the colorMode property:

pages/light.vue
<template>
  <h1>This page is forced with light mode</h1>
</template>

<script>
export default {
  colorMode: 'light',
}
</script>

This feature is perfect for implementing dark mode to a website incrementally by setting the not-ready pages to colorMode: 'light'.

We recommend to hide or disable the color mode picker on the page since it won't be able to change the current page color mode, using $colorMode.forced value.

Example

You can see a more advanced example in the example/ directory or play online with the CodeSandBox below:

Loading CodeSandbox...

Configuration

You can configure the module by providing the colorMode property in your nuxt.config.js, here are the default options:

colorMode: {
  preference: 'system', // default value of $colorMode.preference
  fallback: 'light', // fallback value if not system preference found
  hid: 'nuxt-color-mode-script',
  globalName: '__NUXT_COLOR_MODE__',
  componentName: 'ColorScheme',
  classPrefix: '',
  classSuffix: '-mode',
  storageKey: 'nuxt-color-mode'
}

Notes:

  • 'system' is a special value, it will automatically detect the color mode based on the system preferences (see prefers-color-mode spec). The value injected will be either 'light' or 'dark'. If no-preference is detected or the browser does not handle color-mode, it will set the fallback value.

Caveats

When $colorMode.preference is set to 'system', using $colorMode in your Vue template will lead to a flash. This is due to the fact that we cannot know the user preferences when pre-rendering the page since they are detected on client-side.

To avoid the flash, you have to guard any rendering path which depends on $colorMode with $colorMode.unknown to render a placeholder or use our <ColorScheme> component.

Example:

<template>
  <ColorScheme placeholder="..." tag="span">
    Color mode: <b>{{ $colorMode.preference }}</b>
    <span v-if="$colorMode.preference === 'system'">(<i>{{ $colorMode.value }}</i> mode detected)</span>
  </ColorScheme>
</template>

Props:

  • placeholder: String
  • tag: String, default: 'span'

TailwindCSS

Tailwind v2

Tailwind v2 introduced dark mode, in order to work with @nuxtjs/color-mode, you need to set darkMode: 'class' in your tailwind.config.js:

tailwind.config.js
module.exports = {
  darkMode: 'class'
}

Then in your nuxt.config.js, set the classSuffix option to an empty string:

nuxt.config.js
export default {
  colorMode: {
    classSuffix: ''
  }
}

Checkout the live example on CodeSandBox.

Tailwind Dark Mode Plugin

You can easily integrate this module with tailwindcss-dark-mode by just setting darkSelector: '.dark-mode', see changing the selector documentation.

// tailwind.config.js
module.exports = {
  theme: {
    darkSelector: '.dark-mode'
  },
  variants: {
    backgroundColor: ["dark", "dark-hover", "dark-group-hover", "dark-even", "dark-odd", "hover", "responsive"],
    borderColor: ["dark", "dark-focus", "dark-focus-within", "hover", "responsive"],
    textColor: ["dark", "dark-hover", "dark-active", "hover", "responsive"]
  },
  plugins: [
    require('tailwindcss-dark-mode')()
  ]
}

Checkout a live example on CodeSandBox as well as @nuxtjs/tailwindcss module.

Contributing

You can contribute to this module online with CodeSandBox:

Edit @nuxtjs/color-mode

Or locally:

  1. Clone this repository
  2. Install dependencies using yarn install or npm install
  3. Start development server using yarn dev or npm run dev

License

MIT License

Copyright (c) NuxtJS Team

Edit this page on GitHub Updated at Wed, Feb 16, 2022