Documentation

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


v3 of @nuxtjs/color-mode is compatible with Nuxt 3 and Nuxt Bridge. If you're looking for the previous version of this module, check out the previous docs, or read more about the differences.

Features

  • Nuxt 3 and Nuxt Bridge support
  • Add .${color}-mode class to <html> for easy CSS theming
  • Force a page to a specific color mode (perfect for incremental development)
  • Works with client-side and universal rendering
  • Auto detect system color-mode
  • Sync dark mode across tabs and windows 🔄
  • Supports IE9+ 👴

Live demo

Checkout the online demo.

Setup

@nuxtjs/color-mode version 3 supports Nuxt Bridge and Nuxt 3 only. For use in Nuxt 2 (without Bridge), make sure to install version 2.

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

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

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

nuxt.config.js
import { defineNuxtConfig } from 'nuxt'export default defineNuxtConfig({  modules: ['@nuxtjs/color-mode']})

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

Usage

You can access the color mode helper by either calling useColorMode() or accessing $colorMode directly in your template. This helper has the following properties:

  • 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><script setup>  const colorMode = useColorMode()  console.log(colorMode.preference)</script><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>// For Nuxt Bridgeexport default {  colorMode: 'light',}// For Nuxt 3definePageMeta({  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 playground/ directory or play online with the CodeSandBox below:

Loading Sandbox...

Configuration

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

nuxt.config.js
import { defineNuxtConfig } from 'nuxt'export default defineNuxtConfig({  modules: ['@nuxtjs/color-mode'],  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
import { defineNuxtConfig } from 'nuxt'export default defineNuxtConfig({  modules: ['@nuxtjs/color-mode'],  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.

Migrating to v3

v3 of @nuxtjs/color-mode requires either Nuxt Bridge or Nuxt 3. (If you are using Nuxt 2 without Bridge, you should continue to use v2.)

  1. The main change between Nuxt 2 -> Nuxt 3 is that you will define your color mode at the page level with definePageMeta:
  <template>    <h1>This page is forced with light mode</h1>  </template>  <script>- export default {-   colorMode: 'light',- }+ definePageMeta({+   colorMode: 'light',+ })  </script>

⚠️ If you are using Nuxt Bridge, you should not use definePageMeta but instead continue using the component option colorMode.

  1. The $colorMode helper remains the same, but there is also a new composable (useColorMode) which is the recommended way of accessing color mode information.
  2. If you were directly importing color mode configuration types, note that this has been renamed to ModuleOptions.

Contributing

You can contribute to this module online with CodeSandBox:

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) Nuxt Team