Dark and Light mode with auto detection made easy with Nuxt 🌗
@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..${color}-mode
class to <html>
for easy CSS themingCheckout the online demo.
@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 add --dev @nuxtjs/color-mode
Then, add @nuxtjs/color-mode
to the modules
section of your 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 ✨
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 modevalue
: Useful to know what color mode has been detected when $colorMode === 'system'
, you should not update itunknown
: Useful to know if during SSR or Generate, we need to render a placeholderforced
: 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>
You can force the color mode at the page level (only parent) by setting the colorMode
property:
<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'
.
$colorMode.forced
value.You can see a more advanced example in the playground/ directory or play online with the CodeSandBox below:
You can configure the module by providing the colorMode
property in your nuxt.config.js
; here are the default options:
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.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'
Tailwind v2 introduced dark mode, in order to work with @nuxtjs/color-mode
, you need to set darkMode: 'class'
in your tailwind.config.js
:
module.exports = { darkMode: 'class'}
Then in your nuxt.config.js
, set the classSuffix
option to an empty string:
import { defineNuxtConfig } from 'nuxt'export default defineNuxtConfig({ modules: ['@nuxtjs/color-mode'], colorMode: { classSuffix: '' }})
Checkout the live example on CodeSandBox.
You can easily integrate this module with tailwindcss-dark-mode by just setting darkSelector: '.dark-mode'
, see changing the selector documentation.
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.
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.)
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
.
$colorMode
helper remains the same, but there is also a new composable (useColorMode
) which is the recommended way of accessing color mode information.ModuleOptions
.You can contribute to this module online with CodeSandBox:
Or locally:
yarn install
or npm install
yarn dev
or npm run dev
Copyright (c) Nuxt Team