theme in storage

next.js (pages dir) + tailwind I want my user to click button. button adds a class of dark to the html tag, and tailwind updates all utilities with their dark counterpart. the button also sets local storage with a theme of dark. I want my user to leave or refresh the page to see their dark mode. the problem: when a user refreshes the page, the page loads as light mode then dark. I try to access my local storage beforehand or render null with code similar to this SO answer: https://stackoverflow.com/a/74134368 but that doesnt work. so how can I access my user's stored theme before a page first paints?
Stack Overflow
How to fix dark mode background color flicker in NextJS?
So my issue is that Next.js does not have access to localStorage on the client side and thus will ship HTML that by default either does or does not have class="dark". This means that when...
12 Replies
Sybatron
Sybatron2y ago
Dark Mode - Tailwind CSS
Using Tailwind CSS to style your site in dark mode.
Silas | @silaspath
this is understood. the 'class' option is selected
del.hydraz
del.hydraz2y ago
The way I usually do it is have a boolean in local storage that tracks the theme and a function that runs whenever the state of that boolean changes, adding the "dark" class to the body tag when dark=true and removing it when dark=false. You could also use whatever state management you'd like, so long as you can select the body tag and add that utility class. Does that help?
Silas | @silaspath
sorta. the problem was that the light them would flash before the browser did find the local storage and set it to dark
jdsl
jdsl2y ago
The server-side rendering doesn't know that user's local storage and you get hit with the light mode first.
Neto
Neto2y ago
you can use css root variables
Silas | @silaspath
though you all have nudged me in the right direction and I think I found the best answer... turns out I should put this code in _app ...
if (typeof window !== "undefined") {
let storedTheme = localStorage?.getItem("theme");
if (!storedTheme) storedTheme = "light";
document.documentElement.classList.add(storedTheme);
}
if (typeof window !== "undefined") {
let storedTheme = localStorage?.getItem("theme");
if (!storedTheme) storedTheme = "light";
document.documentElement.classList.add(storedTheme);
}
like edit globals.css?
Neto
Neto2y ago
https://github.com/STNeto1/tw-react-theme
theme: {
extend: {
colors: {
primary: 'var(--color-primary)',
secondary: 'var(--color-secondary)'
}
}
},
theme: {
extend: {
colors: {
primary: 'var(--color-primary)',
secondary: 'var(--color-secondary)'
}
}
},
useEffect(() => {
document.documentElement.style.setProperty('--color-primary', theme.primary)
document.documentElement.style.setProperty(
'--color-secondary',
theme.secondary
)
}, [theme])
useEffect(() => {
document.documentElement.style.setProperty('--color-primary', theme.primary)
document.documentElement.style.setProperty(
'--color-secondary',
theme.secondary
)
}, [theme])
about the flash on screen you will have to eat the flash, there is no way of using it without local storage and time to sync
del.hydraz
del.hydraz2y ago
Yeah, the way to deal with the flicker is to run the code server-side, but idk how to get the data from local storage to the server to render it correctly If you know this code runs on the server, then you should be all good and the flicker should go away
jdsl
jdsl2y ago
For SSR, you can set the theme preference in the user profile (db) or cookie
del.hydraz
del.hydraz2y ago
Ooh, cookie is a good idea
Silas | @silaspath
// imports~

if (typeof window !== "undefined") {
let storedTheme = localStorage?.getItem("theme");
if (!storedTheme) storedTheme = "light";

document.documentElement.classList.add(storedTheme);
}

const MyApp: AppType<{ session: Session | null }> = ({
Component,
pageProps: { session, ...pageProps },
}) => {
return (
<SessionProvider session={session}>
<Layout>
<Component {...pageProps} />
</Layout>
</SessionProvider>
);
};

export default api.withTRPC(MyApp);
// imports~

if (typeof window !== "undefined") {
let storedTheme = localStorage?.getItem("theme");
if (!storedTheme) storedTheme = "light";

document.documentElement.classList.add(storedTheme);
}

const MyApp: AppType<{ session: Session | null }> = ({
Component,
pageProps: { session, ...pageProps },
}) => {
return (
<SessionProvider session={session}>
<Layout>
<Component {...pageProps} />
</Layout>
</SessionProvider>
);
};

export default api.withTRPC(MyApp);
Want results from more Discord servers?
Add your server