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...
28 Replies
i think you need this https://tailwindcss.com/docs/dark-mode
Dark Mode - Tailwind CSS
Using Tailwind CSS to style your site in dark mode.
this is understood. the 'class' option is selected
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?sorta. the problem was that the light them would flash before the browser did find the local storage and set it to dark
The server-side rendering doesn't know that user's local storage and you get hit with the light mode first.
you can use css root variables
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
...
like edit globals.css?https://github.com/STNeto1/tw-react-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
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
For SSR, you can set the theme preference in the user profile (db) or cookie
Ooh, cookie is a good idea
This is how I do it, but I'm running this function in an Astro script tag:
I'm more of a fan for this being sitewide
Correct me if I'm wrong, but I think storing it in a cookie will allow it to work sitewide because on each page request you can send the cookie along with the rest of the request. Next can then take that cookie and you can execute whatever utility class adding logic you'd like on server side
if I were to implement that, each page must then use getStaticProps? or would middleware be involved?
I think you'd either need
getStaticProps
for each page, or a way to inject it into the entire app each time, like using a layout where you have access to the body tag and can slap utility classes on it at will
Sorry I'm still learning how Next handles its pages and layouts and such, so take what I say there with a grain of saltLet me check an older project. I was doing it in the _app.tsx I think for the whole project
You can also use middleware
thanks, so to make sure, it worked out for you?
I used this in a previous Next12 project (before T3) and it would keep the layouts without any flashing.
Might not be the most elegant solution, but it's something to build from.
How did you handle it calling itself recursively? Sorry if a bit off-topic
Good catch, I renamed that before I posted. It was
CompanyApp.getinitialProps =...
But I removed company name before posting it hereAh ok, yeah happy to
Fixed it
These days I'd probably go with middleware if I already had middleware firing for each page
@joerambo thanks for the tips. I haven't implemented the middleware option yet but I commented in the code that I should much, much later
an amazing amount of effort was put on this.
more of a react problem than anything else haha.
Yeah I remember struggling with this concept earlier and trying out different ideas. Ran into things that worked, but would cause other problems down the line. I'm sure with RSC this will all change again shortly.
(for the better)
All good if this is marked as the answer for indexing?