Next.js Discord

Discord Forum

Theme flicker on page load

Answered
Iridescent shark posted this in #help-forum
Open in Discord
Iridescent sharkOP
Hiya, I've implemented a theme switching system on my (tailwind) site. This works fine, however, I have a sort of FOUC situation where if any page is loaded it takes some time (~200ms) for the theme to load in. So if the user is using a dark theme, a light theme (the default), will appear first and then switch to dark.

How can I prevent this from happening? Here is the code I use:
// darkMode: "class"
// usage example: dark:text-white text-black

export default function Theme() {
  const [theme, setTheme] = useState("light");

  useEffect(() => {
    const storedTheme = localStorage.getItem("theme");
    if (storedTheme) {
      setTheme(storedTheme);
    }
  }, []);

  useEffect(() => {
    const root = window.document.documentElement;
    if (theme === "dark") {
      root.classList.add("dark");
    } else {
      root.classList.remove("dark");
    }
  }, [theme]);
  // ... theme switching logic
Answered by Asian black bear
You might want to use next-themes which prevents FUOC altogether without you having to reinvent the wheel.
View full answer

7 Replies

Asian black bear
You might want to use next-themes which prevents FUOC altogether without you having to reinvent the wheel.
Answer
Iridescent sharkOP
Yeah, that's probably smarter.. I assume it integrates with tailwind if I'm reading this correctly?
Note! If you set the attribute of your Theme Provider to class for Tailwind next-themes will modify the class attribute on the html element. See With TailwindCSS.
Nevermind lol I didn't even see the 'with tailwind' section.. I'll go try it out!
Asian black bear
Yeah it will integrate with Tailwind when using the class attribute allowing you to use dark:.
Just make sure to pay attention when reading the readme which mentions that you have to use suppressHydrationErrors on the root element which people often forget.
Iridescent sharkOP
Where do I have to put that exactly? I have this in my layout now but I still receive the hydration errors. In the stack trace I see it being applied to the body as well (I'll try this: https://github.com/pacocoursey/next-themes?tab=readme-ov-file#avoid-hydration-mismatch)

  return (
    <html lang="en" suppressHydrationWarning>
      <head />
      <body>
        <ThemeProvider attribute="class">
          <Header />
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
Yeah fixed it by waiting for it to be mounted, thanks!