Coder Social home page Coder Social logo

joserfelix / react-css-theme-switcher Goto Github PK

View Code? Open in Web Editor NEW
101.0 2.0 10.0 1.25 MB

๐Ÿ’ซ Switch between CSS themes using React

Home Page: https://react-css-theme-switcher.netlify.app/

License: MIT License

HTML 3.39% TypeScript 95.02% CSS 0.52% JavaScript 1.07%

react-css-theme-switcher's Introduction

React CSS Theme Switcher

Version License: MIT codecov PRs Welcome Bundle size

๐Ÿ’ซ Switch between CSS themes using React

Prerequisites

  • node >=10

Installation

npm i react-css-theme-switcher

or with Yarn:

yarn add react-css-theme-switcher

Usage

Import ThemeSwitcherProvider and pass a theme object with the names of the themes and their respective paths to the CSS stylesheet (normally, public folder).

import React from 'react';
import ReactDOM from 'react-dom';

import { ThemeSwitcherProvider } from 'react-css-theme-switcher';

const themes = {
  light: 'public/light.css',
  dark: 'public/dark.css',
};

const App = () => {
  return (
    <ThemeSwitcherProvider defaultTheme="light" themeMap={themes}>
      <Component />
    </ThemeSwitcherProvider>
  );
};

Use useThemeSwitcher Hook:

import { useThemeSwitcher } from 'react-css-theme-switcher';

const Component = () => {
  const { switcher, themes, currentTheme, status } = useThemeSwitcher();
  const [isDarkMode, setIsDarkMode] = React.useState(false);

  if (status === 'loading') {
    return <div>Loading styles...</div>;
  }

  const toggleDarkMode = () => {
    setIsDarkMode(previous => {
      switcher({ theme: previous ? themes.light : themes.dark });
      return !previous;
    });
  };

  return (
    <div>
      <h2>Current theme: {currentTheme}</h2>
      <button onClick={toggleDarkMode} />
    </div>
  );
};

CSS Injection Order

react-css-theme-switcher provides a way to avoid collision with other stylesheets or appended styles by providing where to inject the styles. To achieve this, add an HTML comment like <!--inject-styles-here--> somewhere on the head and then provide 'inject-styles-here' or your custom name in the insertionPoint prop in ThemeSwitcherProvider.

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      @import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');

      * {
        color: inherit;
      }

      html {
        font-family: 'Poppins', sans-serif;
      }
    </style>
    <!-- inject-styles-here -->
    <title>Playground</title>
  </head>

  <body>
    <div id="root"></div>
  </body>
</html>
const App = () => {
  return (
    <ThemeSwitcherProvider
      defaultTheme="light"
      insertionPoint="inject-styles-here"
      themeMap={themes}
    >
      <Component />
    </ThemeSwitcherProvider>
  );
};

HTML Element Insertion Point

Some libraries and frameworks make it hard to use comments in head for handling injection order. To solve this issue, you can provide a DOM element as the insertion point. Take for example a <noscript></noscript> element:

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      @import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');

      * {
        color: inherit;
      }

      html {
        font-family: 'Poppins', sans-serif;
      }
    </style>
    <noscript id="inject-styles-here"></noscript>

    <title>Playground</title>
  </head>

  <body>
    <div id="root"></div>
  </body>
</html>
const App = () => {
  return (
    <ThemeSwitcherProvider
      defaultTheme="light"
      insertionPoint={document.getElementById('inject-styles-here')}
      themeMap={themes}
    >
      <Component />
    </ThemeSwitcherProvider>
  );
};

API

ThemeSwitcherProvider

Props

Name Type Default value Description
attr String data-theme Attribute name for that will be appended to the body tag. Its value will be the current theme name.
defaultTheme String Default theme to load on mount. Must be in themeMap
id String current-theme-style Id of the current selected CSS.
insertionPoint String or HTMLElement Comment string or element where pre-fetch styles and current themes will be injected. The library will look for the comment string inside head element. If missing will append styles at the end of the head. This is useful for CSS override.
themeMap Object Object with all themes available. Key is the theme name and the value is the path for the CSS file.

useThemeSwitcher

Returns

Name Type Default value Description
currentTheme String or Undefined undefined Current selected theme
themes Object themeMap keys All themes supplied in the themeMap.
switcher ({ theme }: { theme: string }) => void; Function Function to change themes.
status enum('idle', 'loading', 'loaded') idle Current load status of the selected stylesheet. Useful to prevent flicker when changing themes.

Contributors

Thanks goes to these wonderful people (emoji key):


Jose Felix

๐Ÿ’ป ๐Ÿ“– โš ๏ธ

This project follows the all-contributors specification. Contributions of any kind are welcome!

Show your support

Give a โญ๏ธ if this project helped you!

react-css-theme-switcher's People

Contributors

dependabot[bot] avatar elis avatar joserfelix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

react-css-theme-switcher's Issues

ThemeSwitcherProvider is not working at Next.js

import React from 'react';
import App from 'next/app';
import Head from 'next/head';
import {Provider} from 'react-redux';
import withRedux from 'next-redux-wrapper';
import ThemeProvider from '../containers/ThemeProvider';
import initStore from '../redux/store';
import '@glidejs/glide/dist/css/glide.core.min.css';
import 'react-quill/dist/quill.snow.css';
import 'react-quill/dist/quill.core.css';
import '../style/global.css';
import 'react-image-crop/dist/ReactCrop.css'
import { ThemeSwitcherProvider } from 'react-css-theme-switcher';

const themes = {
  light: 'antd/dist/antd.css',
  dark: 'antd/dist/antd.dark.css',
};

class CustomApp extends App {
  render() {
    const {Component, pageProps, store, router} = this.props;
    let component = <Component {...pageProps} />;
    return (
      <ThemeSwitcherProvider defaultTheme="light" themeMap={themes}>
        <Provider store={store}>
          <ThemeProvider>
            <Head>
              <title>KTX Admin</title>
            </Head>
            {component}
          </ThemeProvider>
        </Provider>
      </ThemeSwitcherProvider>
    );
  }
}

export default withRedux(initStore)(CustomApp);

"antd": "^4.18.8",
"next": "^11.1.2",
"react": "^17.0.2",
react-css-theme-switcher:0.3.0

I try to change different antd.css file at Next.js
But ThemeSwitcherProvider is not working....

Support Parcel v2

Following path throws an error during builds when using parcel v2 bundler.

Changing it to dist/react-css-theme-switcher.esm.js from dist/react-theme-switcher.esm.js seems to fix the issue.

"module": "dist/react-theme-switcher.esm.js",

Reduce .less file size

Hi,

I'm using webpack and I was wondering is there a way to reduce light/dark .less file size since its importing the entire styles library? Not really an issue just looking for ways to optimize overall app bundle size

No effect on changing switching themes using different color variables for scss files

I am using three separate theme modes and I am using themeswitcherprovider at top and is wrapping a route path and in that component of route path i am using themeswitcher to switch it and using three separate scss files to represent different color variables and using useEffect() to use themeswitcher using switcher function to change the selected theme but it has no effect but while changing it is giving

Refused to apply style from 'https://0.0.0.0:8085/scss/defaultTheme.scss' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.

Add an option to embed the styles instead of linking

Use case

I can't make this plugin work because my css theme files are shipped as npm package and i have to import from node_modules.

Suggestion

Adding a prop or option to use <style>...</style> instead of the <link> would solve this issue and #2 because we can tell webpack to import the content of such css as string and not as js module, and then put the content inside the <style> element.

Keeping the dark theme

Dark theme works fine in my project. But when I refresh the page the dark theme is gone. How can I prevent this?

How to use with imports from a module?

Hey @JoseRFelix

I found your post at the Ant Design repository and to me this approach looks nice. Thank you for making this.

Currently I'm trying to figure how to use this while importing styles from a package, like that of Ant Design? Particularly; how will a map of strings make it possible to resolve imports and package them at build time?

data-theme doesnt change correctly

I am trying to use this package with use-dark-mode in Next-JS. I need to switch between light and dark mode. Here's a brief mechanism of how this works:

  1. use-dark-mode fetches value from local state for theme, it passes that to "value" argument in REACT HOOK
  2. This "value" is used as a boolean, if true, switch to dark else keep light theme.

Problem: When i switch between light or dark mode, data-theme="light" or data-theme="dark" just gets stuck. Lets suppose, i am on light mode. i click switch to dark, the data-theme attribute doesn't change value from light to dark. No matter how many times i click it.

Changing colors through variables in less files

Hello @JoseRFelix .
I use your https://github.com/JoseRFelix/antd-dark-mode/tree/master as the basis of my own. The theme switcher works great. The question is how can I change colors for themes. I am trying to change the values of variables in less files. For example in dark-theme.less:
@ primary-color: red

But this has no effect. The only way that works is to change the colors directly in the css dark-theme.css of the file that are in public folder. This is not very convenient (
Tell me how to more correctly and quickly change the base colors of themes. Thank you so much.

Flicker issue?

I have followed your docs but I have a flicker issue when using with Antd library. I'm not sure what could be the cause of it. Would it be because there's a delay loading the switched theme file and it is applied once it's loaded, if so how can I sync everything together?

Flicker

    <Layout>
      <Header
        style={{
          position: "fixed",
          zIndex: 1,
          width: "100%",
          padding: "0 28px",
        }}
      >
        <Row
          type="flex"
          justify="space-between"
          align="middle"
          style={{ height: "100%" }}
        >
          <Col>
            <Title level={3} style={{ margin: 0 }}>
              Chats
            </Title>
          </Col>
          <Col>
            <Toggle />
          </Col>
        </Row>
      </Header>
      <Content
        style={{
          marginTop: 57,
          height: "calc(100vh - 57px)",
        }}
      ></Content>
    </Layout>
const Toggle = () => {
  const dispatch = useDispatch();
  const mode = useSelector(currentMode);
  const { switcher, status, themes } = useThemeSwitcher();

  const handleChange = () => {
    dispatch(onChangeMode());
    switcher({ theme: mode ? themes.light : themes.dark });
  };

  // Avoid theme change flicker
  if (status === "loading") {
    return null;
  }

  return <Switch checked={mode} onChange={handleChange} />;
};

How to use it with Babel and Webpack

I am using antd by importing to Babel and implemented dark mode using this package.

// .babelrc
"plugins": [
    [
      "import", {
        "libraryName": "antd",
        "style": "css"
      }
    ],
]

It works fine, but the problem goes back to the default style after a while.
Maybe it's using a Babel.

even use next.js and the code seems to need to be set up because it is splitting.

Is there any way to solve this problem?

React Testing Warning: Insertion point 'styles-insertion-point' does not exist.

Hi, is anybody getting this warning when using jest to test a screen with it?

    console.warn
      Insertion point 'styles-insertion-point' does not exist. Be sure to add comment on head and that it matches the insertionPoint

      at insertStyle (node_modules/react-css-theme-switcher/src/index.tsx:54:19)
      at switcher (node_modules/react-css-theme-switcher/src/index.tsx:100:9)
      at node_modules/react-css-theme-switcher/src/index.tsx:113:7
      at invokePassiveEffectCreate (node_modules/react-dom/cjs/react-dom.development.js:23487:20)
      at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14)
      at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:318:25)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)

Screen Shot 2022-04-15 at 12 28 21 PM

Scroll to top on theme change

If I change the theme, it will change the dom object and so react is forced to scroll to top ? is there any way to prevent this behavior ?

Webpage not loading CSS when I navigate to a specific URL (react router) from address bar

Hi,

I am very stuck on an issue with my application and was wondering if you may have an idea. This could very well be something I am doing wrong or may be a bug. My app is using "react-router-dom": "^5.2.0", I have your switcher around the with multiple Routes. Here is a rough sample

<ThemeSwitcherProvider
      defaultTheme={darkMode.value ? 'dark' : 'light'}
      themeMap={themes}
      insertionPoint="inject-styles-here"
    >
      <Router>
        <AuthProvider>
          <ScrollToTop>

            <Switch>
              <Route exact path="/">
                <Redirect to="/home" />
              </Route>

              <PrivateRoute path='/home' component={Home} />
              <PrivateRoute path='/profile' component={Profile} />
              <PrivateRoute path='/x/search' component={y} />
              <PrivateRoute path='/x/tags' component={z} />
              <PrivateRoute path='/x' component={x} />
              <PrivateRoute path={'/a/:aId'} component={a} />
              <PrivateRoute path='/a' component={a} />

            </Switch>

          </ScrollToTop>
        </AuthProvider>
      </Router>
    </ThemeSwitcherProvider >

Navigating throughout my app, the css loads/works fine but on some routes, if I navigate directly to it from the address bar, no CSS loads at all. I was wondering if you have any ideas as to why this could be or how I can debug. I see no differences between the components which is why I am stumped.

Thanks for this library and your blog post - excellent stuff

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.