skip to Main Content

I’m having trouble with adding className for my bar before the page loads; I succeeded in adding it for my HTML tag but failed to add it to my bar. I store my theme in localStorage and get it from ThemeLoader. I’m using Nextjs for my page.

Here is the code snip ThemeLoader:

import React from "react";
import Head from "next/head";
import { useEffect } from "react";
const ThemeLoader = ({ theme, setTheme, setThemeUse, themeProvider }) => {
  useEffect(() => {
    const isFirstTimeOnPage = !localStorage.getItem("userTheme");

    if (isFirstTimeOnPage) {
      const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
        .matches
        ? "dark"
        : "light";
      setTheme(systemTheme);
      localStorage.setItem("userTheme", systemTheme);
      setThemeUse(
        systemTheme === "light" ? themeProvider[0] : themeProvider[1]
      );
    } else {
      const savedTheme = localStorage.getItem("userTheme");
      setTheme(savedTheme);
      setThemeUse(savedTheme === "light" ? themeProvider[0] : themeProvider[1]);
    }

    const themeChangeListener = (e) => {
      const newTheme = e.matches ? "dark" : "light";
      setTheme(newTheme);
      setThemeUse(newTheme === "light" ? themeProvider[0] : themeProvider[1]);
      localStorage.setItem("userTheme", newTheme);
    };

    window
      .matchMedia("(prefers-color-scheme: dark)")
      .addEventListener("change", themeChangeListener);

    return () => {
      window
        .matchMedia("(prefers-color-scheme: dark)")
        .removeEventListener("change", themeChangeListener);
    };
  }, [setTheme, setThemeUse, themeProvider]);

  useEffect(() => {
    document.documentElement.className =
      theme === "light" ? "light-theme" : "dark-theme";
  }, [theme]);
  return (
    <Head>
      <style>
        {`
            :root {
              --background-color-light: #ffffff;
              --background-color-dark: #000000;
              --text-color-light: #000000;
              --text-color-dark: #ffffff;
            }
            
            html.light-theme {
              background-color: var(--background-color-light);
              color: var(--text-color-light);
            }
            
            html.dark-theme {
              background-color: var(--background-color-dark);
              color: var(--text-color-dark);
            }

            /* Đặt theme ngay lập tức */
            html {
              background-color: var(--background-color-light);
              color: var(--text-color-light);
              transition: background-color 0.25s ease-out, color 0.25s ease-out;
            }
          `}
      </style>
      <script
        dangerouslySetInnerHTML={{
          __html: `
              (function() {
                var userTheme = localStorage.getItem('userTheme');
                if (userTheme) {
                  document.documentElement.className = userTheme === 'dark' ? 'dark-theme' : 'light-theme';
                } else {
                  var systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
                  document.documentElement.className = systemTheme === 'dark' ? 'dark-theme' : 'light-theme';
                }
              })();
            `,
        }}
      />
    </Head>
  );
};

export default ThemeLoader;

Here are my Bar tags and CSS:

<nav id="bar" className={"Bar--container Bar--" + theme}>
...

And CSS for changing theme:

.Bar--dark{
    background: rgba(22, 22, 22, 1);
    border: 1px solid hsl(0 0% 100% / 0.077);
}

.Bar--light{
    background: #fefefe;
    border: 1px solid rgb(0, 0, 0, 0.1);
}

I want it loaded like this when loading into website

<nav id="bar" className="Bar--container Bar--dark">
...

Thank you!

2

Answers


  1. Chosen as BEST ANSWER

    Here is the answer for me:

    <script
            dangerouslySetInnerHTML={{
              __html: `
                  (function() {
                    var userTheme = localStorage.getItem('userTheme');
                    //I put this in here
                    document.getElementById("bar").className = "Bar--container Bar--" + (localStorage.getItem('userTheme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'));
                    if (userTheme) {
                      document.documentElement.className = userTheme === 'dark' ? 'dark-theme' : 'light-theme';
                    } else {
                      var systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
                      document.documentElement.className = systemTheme === 'dark' ? 'dark-theme' : 'light-theme';
                    }
                  })();
                `,
            }}
          />
    

  2. clsx is generally used to conditionally apply a given className

    This syntax means that some class will only be applied if a given condition evaluates to true

    There are many supported syntax that you can check in the official [docs][1]
    
    
    
    <nav id="bar" className={clsx("Bar--container Bar", theme === "dark" ? "--dark" : "--light")}>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search