nextra
nextra copied to clipboard
Automatic dark mode based on system preferences
macOS 12.3
"next": "^12.1.6",
"nextra": "^1.1.0",
"nextra-theme-docs": "^1.2.6",
Hi, If dark theme is enabled in macOS system preferences, then you still have to manually enable dark mode on the website. Is it a known issue/limitation? Would be nice if it could follow system preferences.
Another case:
- light theme is ON in system preferences
- open nextra based website
- click dark mode button
Actual result: all styling which is added to public/style.css
in @media (prefers-color-scheme: dark) {}
block is ignored.
Hello @chilikasha ,
You can validate if the user prefers dark-mode at page render.
This is an example code:
// _app.js
import { useEffect } from "react"
import "nextra-theme-docs/style.css"
const PREFERS_DARK_MODE = "(prefers-color-scheme: dark)"
export default function Nextra({ Component, pageProps }) {
useEffect(() => {
// https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener
function handleColorScheme(e) {
const prefersDarkMode = e && e.matches
const prefersLightMode = !prefersDarkMode
const darkActive = document.querySelector(".dark")
const lightActive = !darkActive
const toggleButton = document.querySelector("nav [aria-label*='theme']")
if (
(prefersDarkMode && lightActive) ||
(prefersLightMode && darkActive)
) {
if (toggleButton) {
// If button exists we trigger click event
toggleButton.click()
} else {
// If content isn't yet available we store user preferences in localStorage
localStorage.setItem("theme", prefersDarkMode ? "dark" : "light")
}
}
}
const matchedMedia = window.matchMedia(PREFERS_DARK_MODE)
matchedMedia.addEventListener("change", handleColorScheme) // We listen to match-media changes
handleColorScheme(matchedMedia) // On-first-render match validation
return () => {
matchedMedia.removeEventListener("change", handleColorScheme)
}
}, [])
return <Component {...pageProps} />
}
This will change to dark-mode if the user expects a dark color scheme.
To consider: Theme will keep changing to dark-mode on reload if dark color scheme is expected, this happens even if the user toggles to light-mode from Nextra UI.
Also left some comments and doc references. Hope this helps.
hi @D3Portillo, thanks for your help! I tried the snippet above and have the following behaviour: set mac theme to dark, open private tab and open my site -> it opens with light theme, but if I refresh the site then dark theme is applied.
I'm glad you tested it @chilikasha .
Here is a solution for the issue you mentioned.
Inside first if condition:
if (toggleButton) {
// If button exists we trigger click event
toggleButton.click()
} else {
const newTheme = prefersDarkMode ? "dark" : "light"
// If content isn't yet available we store user preferences in localStorage
localStorage.setItem("theme", newTheme)
const html = document.querySelector(".dark, .light")
// To render content in dark/light mode we append the desired them in html node
html.classList.remove("dark") // remove .dark if present
html.classList.remove("light") // remove .light if present
html.classList.add(newTheme) // append dark or light as per user prefs.
// Inn case of fire and script above won't work - uncomment line bellow
// setTimeout(()=> location.reload())
}
NOTE: Just in case that won't work - try triggering a reload(uncomment line with setTimeout) to apply new theme.
This feature is available in the new design, but you have to use an alpha version of both nextra
and nextra-theme-docs
.
Updated to beta versions today, but don't see any changes regarding dark mode. Works the same way.
My bad, that was alpha. works fine on beta
Though I still don't understand why if select a scheme different from system's, colors for some custom elements defined in css are not switched.
@media (prefers-color-scheme: dark) {
.tag {
background-color: #2b2b2b;
color: #bbb9bb;
}
}
You can use this:
.dark .tag {
background-color: #2b2b2b;
color: #bbb9bb;
}
The .dark
class will be added to <html>
when one of these 2 conditions is met:
- User set the theme to dark
- User set the theme to system and the system is under the dark mode