A Tailwind CSS plugin that gives you an out-of-the-box, customisable, overridable dark mode.
Nightwind uses the existing Tailwind color palette and your own custom colors to automatically generate the dark mode version of the Tailwind color classes you use.
For example, whenever you use a class like bg-red-600 it gets automatically switched to bg-red-300 in dark mode.
You can see it in action on https://nightwindcss.com
npm install nightwind
Enable the Dark class variant in your tailwind.config.js file.
// tailwind.config.js - Tailwind ^2.0
module.exports = {
darkMode: "class",
// ...
plugins: [require("nightwind")],
}
// tailwind.config.js
module.exports = {
experimental: {
darkModeVariant: true,
applyComplexClasses: true,
},
dark: "class",
// ...
plugins: [require("nightwind")],
}
Nightwind relies on a fixed 'nightwind' class to manage transitions, and a toggled 'dark' class applied on a top level element in the DOM, typically the root element.
You can define your own functions to manage the dark mode (or check the examples below), or use the helper functions included in 'nightwind/helper.js' to get started right away.
By default, the helper functions prevent the dreaded flicker of light mode and allow the chosen color mode to persist on update.
To initialize nightwind, add the following script tag to the head element of your pages.
// React Example
import nightwind from "nightwind/helper"
export default function Layout() {
return (
<>
<Head>
<script dangerouslySetInnerHTML={{ __html: nightwind.init() }} />
</Head>
// ...
</>
)
}
Similarly, you can use the toggle
function to switch between dark and light mode.
// React Example
import nightwind from "nightwind/helper"
export default function Navbar() {
return (
// ...
<button onClick={() => nightwind.toggle()}></button>
// ...
)
}
If you need to selectively choose between light/dark mode, you can use the enable
function. It accepts a boolean argument to enable/disable dark mode.
// React Example
import nightwind from "nightwind/helper"
export default function Navbar() {
return (
// ...
<button onClick={() => nightwind.enable(true)}></button>
// ...
)
}
Nightwind also exports a beforeTransition
function that you can leverage in case you prefer to build your own toggle functions. It prevents unwanted transitions as a side-effect of having nightwind class in the html tag.
Check out the toggle
function in the Nextjs example below for an example of how this could be implemented.
See examples of implementation (click to expand):
This is some examples of what Nightwind does by default:
Due to file size considerations, Nightwind is enabled by default only on the 'text', 'bg' and 'border' color classes, as well as their 'hover' variants.
You can also extend Nightwind to other classes and variants:
Nightwind switches between opposite color weights when switching to dark mode. So a -50 color gets switched with a -900 color, -100 with -800 and so forth.
Note: Except for the -50 and -900 weights, the sum of opposite weights is always 900. To customise how Nightwind inverts colors by default, see how to set up a custom color scale
If you add your custom colors in tailwind.config.js using number notation, Nightwind will treat them the same way as Tailwind's colors when switching into dark mode.
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: "#caf0f8", // becomes primary-900 in dark mode
300: "#90e0ef", // becomes primary-600 in dark mode
600: "#0077b6", // becomes primary-300 in dark mode
900: "#03045e", // becomes primary-50 in dark mode
},
},
},
},
}
Check out color mappings to see how to further customize your dark theme.
Variants and other color classes can be enabled for Nightwind like so:
// tailwind.config.js
module.exports = {
// ...
theme: {
nightwind: {
colorClasses: [
"gradient",
"ring",
"ring-offset",
"divide",
"placeholder",
],
},
},
variants: {
nightwind: ["focus"], // Add any Tailwind variant
},
// ...
}
The 'gradient' color class enables Nightwind for the 'from', 'via' and 'to' classes, allowing automatic dark gradients.
If you want an element to remain exactly the same in both light and dark modes, you can achieve this in Nightwind by adding a 'nightwind-prevent' class to the element.
Note: if you only want some of the colors to remain unchanged, consider using overrides.
To prevent all children of an element to remain unchanged in dark mode, you can add the 'nightwind-prevent-block' class to the element. All descandant nodes of the element will be prevented from switching.
You can customize the name of both classes in your tailwind.config.js file
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
fixedClass: "prevent-switch", // default 'nightwind-prevent'
fixedBlockClass: "prevent-switch-block", // default 'nightwind-prevent-block'
},
},
}
Note: The 'nightwind-prevent' class doesn't work with @apply, so always add it in the html.
Nightwind by default applies a '300ms' transition to all color classes. You can customize this value in your tailwind.config.js file, through the transitionDuration property.
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
transitionDuration: "500ms", // default '300ms'
},
},
}
If you wish to disable transition for a single class, you can add the 'duration-0' class to the element (it's already included in Nightwind).
If you wish to disable the generation of all transition classes, you can do so by setting the same value to false.
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
transitionDuration: false, // default '300ms'
},
},
}
Nightwind by default generates transition classes for 'text', 'bg' and 'border' color classes. This should make most elements transition smoothly without affecting performances.
In your configuration file you can also set the transitionClasses property to 'full' to enable generation of transition classes for all color classes used throughout your website (i.e. rings, divide and placeholder).
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
transitionClasses: "full", // default ['text, 'bg', 'border']
},
},
}
Alternatively, you can also specify which color classes you'd like to generate transition classes for.
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
transitionClasses: ["bg", "ring"], // default ['text, 'bg', 'border']
},
},
}
This configuration allows you to define how one or more color weights convert in dark-mode. Note that these affects all color classes.
For example, you could make all -100 colors switch into -900 colors like so.
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
colorScale: {
100: 900, // default 800
},
},
},
}
Note: These settings can still be overridden for specific colors using color mappings, or in specific elements with overrides
This preset simulates how Nightwind would behave without the -50 color classes. Any -50 color will essentially appear the same as -100 colors (both becomes -900)
This behaviour may be desirable for two main reasons:
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
colorScale: {
preset: "reduced",
},
},
},
}
This is the corresponding scale:
// tailwind.config.js
colorScale: {
50: 900,
100: 900,
200: 800,
300: 700,
400: 600,
500: 500,
600: 400,
700: 300,
800: 200,
900: 100,
},
Note: When using a preset, specific weights will be ignored.
If you're using the important ID selector strategy in your config, such as
// tailwind.config.js
module.exports = {
important: "#app",
}
Please note that Nightwind assumes that the #app element is a parent of the element which contains the toggled 'dark' and 'nightwind' classes.
If you're applying the 'important ID selector' to the same element that contains both the 'nightwind' and the toggled 'dark' classes (typically the root element), enable the following setting:
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
importantNode: true,
},
},
}
Note: Overrides will stop working as they always assume a parent-child relationship between elements.
Color mappings allow you to fine-tune your dark theme, change colors in batch and control how Nightwind behaves in dark mode. You set them up like this:
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
colors: {
// Color mappings go here
},
},
},
}
There are two main ways to map colors in Nightwind: using individual colors or color classes.
You can use the following syntax to specify colors:
You can use this to set individual dark colors, directly from tailwind.config.js
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
colors: {
white: "gray.900",
black: "gray.50",
red: {
100: "#1E3A8A", // or 'blue.900'
500: "#3B82F6", // or 'blue.500'
900: "#DBEAFE", // or 'blue.100'
},
primary: "var(--secondary)",
secondary: "var(--primary)",
},
},
},
}
Note: Contrarily to all other cases, when you individually specify a dark color this way nightwind doesn't automatically invert the color weight. The same is also valid for overrides.
This is useful when you want to switch a whole color class in one go. Consider the following example:
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
colors: {
red: "blue",
yellow: "primary",
pink: "yellow.500",
},
},
extend: {
colors: {
primary: {
50: "#caf0f8",
300: "#90e0ef",
600: "#0077b6",
900: "#03045e",
},
},
},
},
}
You can even specify a default dark color for a color class, as well as individual colors for specific weights. You can do so by specifying a default value for a color class.
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
colors: {
rose: {
default: "blue",
200: "yellow.300",
},
},
},
},
}
The default dark variant allows you to write classes like 'dark:bg-gray-200' (not necessarily related to color classes) that only gets applied when you switch into dark mode.
The 'dark' variant can be used to override the automatic Nightwind classes.
<h2 class="text-gray-900 dark:text-yellow-200">I'm yellow in dark mode</h2>
Note: The 'dark' variant can also be concatenated with both screens and other variants, so you can write classes like 'sm:dark:hover:text-yellow-200'.
Please refer to the Tailwind official documentation to learn more about the 'dark' variant.
If you're using the Typography plugin, you can let Nightwind build an automatic dark mode of all typography color styles.
Note: It will respect all customizations and color mappings specified in your nightwind configuration.
Simply add the following line in your Nightwind theme configuration:
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
typography: true,
},
},
}
To fine-tune your typography dark mode, you can define the single classes by using the individual color syntax (either hex or tailwind-based color codes).
// tailwind.config.js
module.exports = {
theme: {
nightwind: {
typography: {
color: "blue.400",
h1: {
color: "#90e0ef",
},
indigo: {
a: {
color: "purple.300",
},
},
},
},
},
}