Aug 4, 2022
A simple way to switch themes on your website which takes into account users' system preferences.
In this guide, we are using next-themes
, which is a library that makes it easy to manage website themes, including taking into account users' system preferences.
next-theme
We first need to wrap our content in the theme provider. The most convenient place to do it is in templates. So let's create a template, say main
, in the templates
folder, and add the following:
import { ThemeProvider } from "next-themes"
export const Template = ({ children }) => {
return (
<ThemeProvider attribute="class">
<div className="prose dark:prose-invert p-8">
{children}
</div>
</ThemeProvider>)
}
Some notes:
ThemeProvider
to use class
for theming.div
with the prose
and dark:prose-invert
class, which are utility classes from Tailwind that sets up nice typography and color defaults.motif.json
configuration:{
"templates": {
"**/*": "main",
},
// ...
}
Next, let's create a toggle to switch between themes.
import { useTheme } from "next-themes"
import { Moon, Sun } from "react-feather"
export const ThemeSwitcher = () => {
const { resolvedTheme, setTheme } = useTheme()
const [isMounted, setMounted] = useState(false)
const toggleColorMode = () => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')
useEffect(() => {
setMounted(true)
}, [])
return (
<>
{isMounted && (
<button
className="w-4 h-4 cursor-pointer focus:outline-none text-neutral-900 dark:text-white"
onClick={toggleColorMode}
aria-label={`Switch to ${resolvedTheme === 'dark' ? "light" : "dark"} mode`}
>
{resolvedTheme === 'dark' ? <Sun /> : <Moon />}
</button>
)}
</>
)
}
Note the use of an isMounted
flag, which is there to prevent React hydration mismatches.
Let's put the theme switcher in our template, so that it is included on all pages:
<ThemeProvider attribute="class">
<div className="prose dark:prose-invert p-8">
<ThemeSwitcher />
{children}
</div>
</ThemeProvider>
We need to instruct Tailwind to use class
for determining dark mode. In tailwind.config.js
(located at the root of your project), add the following flag:
module.exports = {
darkMode: 'class',
// ...
}
We are all set up. Now we just need to tell what colors/styles to use in dark mode. This is done by adding a dark:
prefix to our Tailwind classes. So for instance if we want a button to have a blue background in light mode and a white background in dark mode, we can specify it as follows:
<button className="bg-blue dark:bg-white">Click me</button>
Any class can be prefixed with the dark:
prefix, so we can customize more than just colors:
<button className="bg-blue dark:bg-white text-white dark:text-black rounded-sm dark:rounded-lg">Click me</button>
To change the website background, we'll want to set the style of our page body, globally in main.css
:
body {
@apply bg-white dark:bg-black;
}
That's it! We now have a dark mode toggle and a way to customize the design when it's on, to our users' delight.
If you want to try out a fully working setup, check out our Highway Docs template →