Royal_lobster
Royal_lobster

Reputation: 137

how to dynamically change global stylesheets in next js

I have two CSS files one for Light theme and other for Dark theme. How to dynamically change the style sheets ?

Here is the code i am currently using in __app.js

import React, { useState, useEffect } from "react";
import "../styles/globals.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";
import { ThemeContext } from "../context/ThemeContext";

function MyApp({ Component, pageProps }) {
  const [theme, setTheme] = useState("light");

  useEffect(() => {
    if (theme == "dark") {
      import("primereact/resources/themes/arya-blue/theme.css");
    }
    if (theme == "light") {
      import("primereact/resources/themes/saga-blue/theme.css");
    }
  }, [theme]);

  return (
    <ThemeContext.Provider value={[theme, setTheme]}>
        <Component {...pageProps} />
    </ThemeContext.Provider>
  );
}

export default MyApp;

This code is working to switch from light theme to dark theme but it fails to switch from dark to light. Is their any better way to do this ?

Upvotes: 5

Views: 7538

Answers (2)

Royal_lobster
Royal_lobster

Reputation: 137

I solved this problem by this blog post with some differences.

1. Created a new Themes.js file which contains both dark mode and light mode styles


const DarkTheme = () => {
  return (
    <style jsx global>
      {`
       Copied here the entire dark mode style sheet from node modules (around 5000 lines)
      `}
    </style>
  );
};

const LightTheme = () => {
  return (
    <style jsx global>
      {`
       Copied here the entire light mode style sheet from node modules (around 5000 lines)
      `}
    </style>
  );
};

export default function Theme({ theme }) {
  if (theme == "dark") {
    return <DarkTheme />;
  }
  return <LightTheme />;
}

2. Used the Themes component inside __App.js file with context and theme persistence with local storage:


import React, { useState, useEffect } from "react";
import Head from "next/head";
import "../styles/globals.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";
import { ThemeContext } from "../context/ThemeContext";
import Theme from "../themes/Theme"; //imported newly created theme file
import PrimeReact from "primereact/api";

function MyApp({ Component, pageProps }) {
  const [theme, setTheme] = useState((typeof window !== "undefined" && localStorage.getItem("theme")) || "light");

  useEffect(() => {
    typeof window !== "undefined" && localStorage.setItem("theme", theme);
  }, [theme]);

  return (
    <>
      <ThemeContext.Provider value={[theme, setTheme]}>
        <Theme theme={theme} /> {//This Component provides dynamic global styles}
          <Component {...pageProps} />
      </ThemeContext.Provider>
    </>
  );
}

export default MyApp;

Upvotes: 4

Ali
Ali

Reputation: 485

The problem is that when switching back to light theme from dark theme your app contains the css of both dark and light themes.

One solution that comes to my mind is to store the theme state in local storage and then reload the page , something like this

Although it has a drawback that upon theme change your website would lose all the other states


import React, { useState, useEffect } from "react";
import "../styles/globals.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";
import { ThemeContext } from "../context/ThemeContext";

function MyApp({ Component, pageProps }) {
  const [theme, setTheme] = useState("light");
  const currentTheme = localStorage.getItem("theme");

  useEffect(() => {
    localStorage.setItem("theme",theme)
    window.location.reload();
  }, [theme]);

  if (currentTheme == "dark") {
      import("primereact/resources/themes/arya-blue/theme.css");
    }
    if (currentTheme == "light") {
      import("primereact/resources/themes/saga-blue/theme.css");
    }

  return (
    <ThemeContext.Provider value={[theme, setTheme]}>
        <Component {...pageProps} />
    </ThemeContext.Provider>
  );
}

export default MyApp;

Upvotes: 3

Related Questions