Nuxt Color Mode
Dark and Light mode with auto detection made easy with Nuxt ๐
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
- Supports IE9+ ๐ด
Live demo
Checkout the online demo and source code.
Setup
@nuxtjs/color-mode
is compatible with Nuxt 3 and Nuxt Bridge. If you're looking for the previous version of this module, check out v2.color-mode.nuxtjs.org, or read more about the differences.
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.ts
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 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>
Force a color mode
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 Bridge
export default {
colorMode: 'light',
}
// For Nuxt 3
definePageMeta({
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.Configuration
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',
dataValue: '',
attrName: '',
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'
. Ifno-preference
is detected or the browser does not handle color-mode, it will set thefallback
value.- Optional
dataValue
andattrName
lets you add dataset or general attribute to thehtml
. for example, if you currently haveclass="dark"
onhtml
,dataValue: 'theme'
will also setdata-theme="dark"
onhtml
,attrName: 'theme-mode'
will settheme-mode="dark"
onhtml
. This is useful when using library like daisyUI or TDesign that usesdata-theme="light"
ortheme-mode="dark"
onhtml
to apply theme.
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 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.ts
, set the classSuffix
option to an empty string:
export default defineNuxtConfig({
modules: ['@nuxtjs/color-mode'],
colorMode: {
classSuffix: ''
}
})
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.)
- 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',
- }
+ <script setup>
+ definePageMeta({
+ colorMode: 'light',
+ })
</script>
โ ๏ธ If you are using Nuxt Bridge, you should not use definePageMeta
but instead continue using the component option colorMode
.
- The
$colorMode
helper remains the same, but there is also a new composable (useColorMode
) which is the recommended way of accessing color mode information. - 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:
- Clone this repository
- Install dependencies using
pnpm install
- Start development server using
pnpm dev
License
Copyright (c) Nuxt Team