How can one prevent the page flash when using class-based dark mode in Tailwind CSS with Next.js v12 without using any 3rd party pkgs like next-themes?
I've looked at:
Do not add <script> tags using next/head (see inline <script>). Use next/script instead. See more info here: https://nextjs.org/docs/messages/no-script-tags-in-head-component<Script strategy="beforeInteractive" src="/scripts/darkMode.js"/> still results in a page flash as it adds defer to it in the head// On page load or when changing themes, best to add inline in `head` to avoid FOUC
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
I think they restrict putting things in Head from v12 to prepare for Suspense / Streaming / React v18.
Either way, I'm lost on how to do it without next-themes, does anyone know how can we just inject that bit of script to prevent that page flash?
Hope this question makes sense, if not, please give me a shout.
I like simple and minimalistic things, hence the aim to reduce the dependency on 3rd party pkgs, such a simple thing should be possible without overcomplicated solution IMO.
I had the same problem and solved it like this in Next 12.1.0:
theme.js within the public folder (mine has the following content):;(function initTheme() {
var theme = localStorage.getItem('theme') || 'light'
if (theme === 'dark') {
document.querySelector('html').classList.add('dark')
}
})()
<Script src="/theme.js" strategy="beforeInteractive" /> to _app.tsx or _app.jsx. This is important - I tried putting it inside _document.tsx which didn't work. The final _app.tsx looks like this:import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Head from 'next/head'
import Script from 'next/script'
function App({ Component, pageProps }: AppProps) {
return <>
<Head>
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<Script src="/theme.js" strategy="beforeInteractive" />
<Component {...pageProps} />
</>
}
export default App
Works like a charm for me - no flickering and all Next.js magic. :) Hope this works for you too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With