How can critical CSS be dynamically added to Next.js using _document.js/_app.js?

I'm currently following the native next.js style approach using css modules. Within my project, I have multiple global css variables defined in theme files that need to be added to the app. Here is an example of what one of these theme files looks like:

// theme.css
:root {
    --PRIMARY_COLOR: #504f94;
    --PRIMARY_BRIGHT_COLOR: #926ba7;
    --PRIMARY_COLOR_ACCENT: #3e3d81;

    --SECONDARY_COLOR: #102f31;
    --SECONDARY_COLOR_ACCENT: #1d2020;

}

The challenge I am facing is that I have several of these theme files in my project and I need to select and use only one based on an environment variable. This decision needs to be made server-side.

My question is, how can I dynamically insert styles into custom _document.js or _app.js after deciding which theme to use? Additionally, I want to ensure that only the selected theme's code gets included in the bundle and not others.

Answer №1

After much consideration, I have devised the following solution:

  1. To start off, in _document.js we will execute a script that utilizes the fs module to read the content of a file containing CSS variables.
  2. We will then proceed to create a style tag with the contents extracted from the file mentioned earlier.
  3. Finally, we will insert the generated tag into the _document component.
import React from 'react';
import { default as Document, Html, Head, Main, NextScript } from 'next/document';
const path = require('path');
const { getRootDirPathEnvVariable } = require('../infrastructure');

export default class MyDocument extends Document {
    render() {
        return (
            <Html lang="en">
                <Head/>
                <body>
                    { this.props.tagToInject}
                    <Main />
                    <NextScript />
                </body>
            </Html>
        );
    }
}


MyDocument.getInitialProps = async ( ctx ) => {

    const cssFileContent = fs
        .readFileSync( path.join( getRootDirPathEnvVariable(), 'src', 'theme.css' ) )
        .toString();

    const tagToInject = (
        <style
                className="css-configs"
                dangerouslySetInnerHTML={ {
                    __html: value,
                } }
         />
    )

    const originalRenderPage = ctx.renderPage;

    ctx.renderPage = () => originalRenderPage( {
        enhanceApp: ( App ) => function EnhanceApp( props ) {
            return (
                <App
                    jsonConfigs={ jsonConfigs }
                    { ...props }
                />
            );
        },
    } );

    const initialProps = await Document.getInitialProps( ctx );

    return {
        ...initialProps,
        tagToInject,
    };
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

expandable div or cell panels

Greetings, I'm facing a challenge with my code: <div id="left"></div> <div id="center"></div> <div id="right"></div> My goal is to ensure that #center always displays at a minimum size, while the other two divs w ...

Click on ng-show to reveal more text in AngularJS

I am attempting to display an ellipsis for the content within a div, along with a '...more' text. Additionally, I am working on using ng-click to show the full text when '....more' is clicked. My goal is to add a hover class upon click ...

The Redux state fails to update on the initial attempt

I have encountered an issue with my state setup and reducer logic. Here is how my state is initialized: const initialState: PhotoState = { photos: [], }; The reducer function is defined as follows: const initialState: PhotoState = { photos: [], }; ex ...

What is the method for customizing the NavBar color using CSS?

Hi there! I recently came across a responsive multi-level menu that caught my eye. After copying the CSS and JavaScript exactly, I ended up with this NavBar. The issue I'm facing is changing the default color (which is green) to another color. Here&ap ...

Using dispatch in Redux does not introduce new information into the store

I am facing an issue with updating the state.data of incomes in my Redux store. I have an array of incomes displayed in a table, with a "+" button to add a new income. When trying to increment the database and Redux store using dispatch, the database gets ...

Cookies are not persisting in the browser even after successful login on a React Node.js application deployed on Render hosting platform

I recently completed a Full-stack MERN (React + Node.js + MongoDB) project by following a tutorial on YouTube. You can check out the tutorial here. The official GitHub repository for this project can be found at https://github.com/codinginflow/MERN-course ...

Unable to apply inline styles to React Component

My Carousel component is supposed to return a collection of carousel boxes, each styled with a specific property. However, I am facing an issue where the style property is not being applied to the returning divs. How can I resolve this? I noticed that whe ...

An error occurred due to RequestHeaderSectionTooLarge after successfully signing in through NextAuth with AzureADProvider

After successfully setting up authentication in my application using NextAuth.js with the AzureADProvider, everything seemed to be working fine. However, I ran into a RequestHeaderSectionTooLarge error after signing in, which appears to be caused by large ...

Tips for understanding nested JSON or array data structure?

My data is stored in a constant called translations and it looks like this: { "item-0": { "_quote-translation": "translation Data", "_quote-translation-language": "English", "_quote-trans ...

Placing elements in Chrome compared to IE

I'm currently attempting to position elements in two rows using mathematical calculations. One of the elements, thumb_container, is a div that is absolutely positioned. Within this container, I am dynamically loading and appending image thumbnails usi ...

Having trouble with the containerElement in React material-ui's MenuItem component?

I'm having an issue with the code below: <MenuItem primaryText="home" containerElement={<Link to="/" />} /> Despite following discussions on other platforms like this one Material UI Menu using routes, adding the containerElement prop to ...

Troubleshooting problem with React Material UI GridList layout

I'm having an issue trying to showcase images in a GridList using Material UI. I've noticed that some of the images have a red gap square between them, which you can see here: example of the current grid layout Here is a snippet of my code for ...

Swap out a div identifier and reload the page without a full page refresh

I am interested in learning how to dynamically remove a div id upon button click and then add it back with another button click to load the associated CSS. The goal is for the page to refresh asynchronously to reflect these changes. So far, I have successf ...

When you first open material-ui cards, there are no default CSS styles applied

https://i.sstatic.net/EVdO8.png My cards created using material-UI are displaying strangely when the page loads or re-loads. Initially, they look different with no apparent CSS styling, but after a few seconds, they appear as intended. I'm not sure i ...

Opt for filling background image instead of stretching it when the screen is resized

My background image resizes with the screen height but stretches when I change the width. The content that should appear below it completely covers the image. This is my current code: HTML: <div id="bg"> <img src="http://placehold.it/2560x1 ...

Having trouble sending `req.params` through http-proxy-middleware in a NodeJS/Express application?

I'm still getting the hang of Node, and I've run into an issue with passing request parameters using http-proxy-middleware. Every time I try, I keep getting a 404 error. This is my express listener setup: app.put("/api/markets/:id",()=>{..c ...

The table width is malfunctioning on Firefox when viewed in HTML

I have been puzzled by the fact that I am unable to adjust the width of the table th in Firefox browser to the smallest value. However, in Chrome browser, this functionality works perfectly. I simply want to divide the values of my td into three rows as sh ...

Dispatching an asynchronous function error in React with TypeScript and Redux - the parameter type is not assignable to AnyAction

Currently, I am in the process of developing a web application that utilizes Firebase as its database, along with Redux and TypeScript for state management. Within my code, I have a dispatch function nested inside a callback function like so: export const ...

JavaScript for Color Swapping on Click Event

While working on coding a website, I attempted to change colors and pictures onclick using JavaScript to edit the CSS. However, the code is only partially functional. Only the "txtArea" field changes color. After checking validators and consoles, everyth ...

Steps for removing the bottom border for the last child in the Material UI Box Component

I have a Box Component where ListItems are wrapped. For each child, I have a border-bottom of 1px solid class set for the Box component, but I don't want it for the last child. How can I achieve that? {data.map((item, i) => { return ...