Jonathan Small
Jonathan Small

Reputation: 1099

Dynamically load .css based on condition in reactJS application

I have a reactJS application that I want to make available to multiple clients. Each clients has unique color schemes. I need to be able to import the .css file that corresponds to the specific client.

For example, if client 1 logs into the application, I want to import client1.css. if client 2 logs into the application, I want to import client2.css. I will know the client number once I have validated the login information.

The application contains multiple .js files. Every .js file contains the following at the top of the file

import React from 'react';
import  { Redirect } from 'react-router-dom';
import {mqRequest} from '../functions/commonFunctions.js';
import '../styles/app.css';

Is there a way to import .css files dynamically for this scenario as opposed to specifying the .css file in the above import statement?

Thank you

Upvotes: 8

Views: 8880

Answers (3)

mezzomix
mezzomix

Reputation: 325

A bit late to the party, I want to expand on @Harmenx answer.

require works in development environments only, once it goes to production you're likely to get errors or not see the css file at all. Here are some options if you, or others, encounter this:

Option 1: Using css modules, assign a variable of styles with the response from the import based on the condition.

  let styles;

  if(this.props.css1 === true) {
     //require('style1.css');
     import("./style1.module.css").then((res) => { styles = res;});
  } else {
     //require('style2.css');
     import("./style2.module.css").then((res) => { styles = res;});
  }

  ...
  <div className={styles.divClass}>...</div>
  ...

Option 2: using Suspend and lazy load from react

// STEP 1: create components for each stylesheet
// styles1.js
import React from "react";
import "./styles1.css";

export const Style1Variables = (React.FC = () => <></>);
export default Style1Variables ;

// styles2.js
import React from "react";
import "./styles2.css";

export const Style2Variables = (React.FC = () => <></>);
export default Style2Variables ;

// STEP 2: setup your conditional rendering component
import React, {lazy, Suspense} from "react";
  
const Styles1= lazy(() => import("./styles1"));
const Styles2= lazy(() => import("./styles2"));

export const ThemeSelector = ({ children }) => {
    return (
        <>
            <Suspense fallback={null} />}>
                {isClient1() ? <Styles1 /> : <Styles2/>}
            </Suspense>
            {children}
        </>
    );
};

// STEP 3: Wrap your app
ReactDOM.render(
        <ThemeSelector>
            <App />
        </ThemeSelector>,
    document.getElementById('root')
);

Option 3: Use React Helm which will include a link to the stylesheet in the header based on a conditional

class App extends Component {
  render() {
    <>
      <Helmet>
        <link
          type="text/css"
          rel="stylesheet"
          href={isClient1() ? "./styles1.css" : "./styles2.css"}
      />
      </Helmet>
      ...
    </>
  }
}

Personally, I like option 2 because you can set a variable whichClientIsThis() then modify the code to:

import React, {lazy, Suspense} from "react";

let clientID = whichClientIsThis();
  
const Styles= lazy(() => import("./`${clientID}`.css")); // change your variable filenames to match the client id.

export const ThemeSelector = ({ children }) => {
    return (
        <>
            <Suspense fallback={null} />}>
                <Styles />
            </Suspense>
            {children}
        </>
    );
};

ReactDOM.render(
        <ThemeSelector>
            <App />
        </ThemeSelector>,
    document.getElementById('root')
);

This way you don't need any conditionals. I'd still recommend lazy loading and suspending so the app has time to get the id and make the "decision" on which stylesheet to bring in.

Upvotes: 5

Harmenx
Harmenx

Reputation: 946

Easy - i've delt with similar before.

componentWillMount() {
  if(this.props.css1 === true) {
     require('style1.css');
  } else {
     require('style2.css');
  }

}

Upvotes: 10

Ben Carp
Ben Carp

Reputation: 26608

Consider using a cssInJs solution. Popular libraries are: emotion and styled-components but there are others as well.

I generally recommend a cssInJs solution, but for what you are trying to do it is especially useful.

In Emotion for example they have a tool specifically build for this purpose - the contextTheme.

What cssInJs basically means is that instead of using different static css files, use all the power of Javascript, to generate the needed css rules from your javascript code.

Upvotes: 3

Related Questions