'React Material-UI v4 - How to control injection order of makeStyles

tldr; How do I ensure makeStyles from the component library is always invoked before the makeStyles of the application that consumes the component library?

My current setup is I have a Common components library that uses Material-UI v4 and is installable from NPM. I export several custom components where each component has its own makeStyles to customize the components styles. Material-UI Core is configured as a devDependency and a peer dependency. My bundler strips out peer dependencies. The goal is to have one version of Material-UI, which would be the version installed as a dependency in the application that consumes the common components library.

In my main application where I install common components library, I want to ensure the makeStyles from the Common Components Library is injected First in the HTML Head so that my makeStyles from my main application that consumes the common components library is injected last in the HTML head.

Here's a code example where I use a Button component from the Common Components Library. The Button component from the Common Components Library has it's own makeStyles styles that are used with useStyles()

Here's the code from the Common Components Library:

import React from 'react';
import PropTypes from 'prop-types';
import {Button, Typography} from '@material-ui/core';
import {makeStyles} from '@material-ui/core/styles';
import classnames from 'classnames';

const useStyles = makeStyles(() => {
  return {
    roundedButton: {
      height: '2.5rem',
      minWidth: '90px',
      lineHeight: '1rem',
      border: '2px solid var(--button-primary)',
      borderRadius: '2rem',
      boxShadow: 'none',
      textTransform: 'capitalize',
      '&:hover': {
        boxShadow: 'none',
      },
    },
    primary: {
      backgroundColor: 'var(--button-primary)',
      color: 'var(--color-white)',
      border: '2px solid transparent',
      '&:hover': {
        backgroundColor: 'var(--button-primary-hover)',
        color: 'var(--color-white)',
      },
    },
    secondary: {
      backgroundColor: 'var(--color-white)',
      color: 'var(--button-secondary)',
      border: '2px solid var(--button-secondary)',
      '&:hover': {
        backgroundColor: 'var(--button-secondary-hover)',
        color: 'var(--button-secondary)',
        border: '2px solid var(--button-secondary)',
      },
    },
    success: {
      backgroundColor: 'var(--color-palmLeaf)',
      color: 'var(--color-white)',
      border: '2px solid transparent',
      '&:hover': {
        backgroundColor: 'var(--color-button-hover-success)',
        color: 'var(--color-white)',
      },
    },
  };
});

export function BaseButton({
  onClick,
  title,
  isDisabled = false,
  color = 'primary',
  variant = 'contained',
  children,
  startIcon,
  endIcon,
  className,
  type = 'button',
}) {
  const classes = useStyles();

  return (
    <Button
      key={title}
      title={title}
      onClick={onClick}
      className={classnames(classes.roundedButton, className)}
      disabled={isDisabled}
      variant={variant}
      color={color}
      startIcon={startIcon}
      endIcon={endIcon}
      type={type}
    >
      <Typography variant="button">{children}</Typography>
    </Button>
  );
}

Here's the code from the application from which I install the library:

import React from 'react';
import {BaseButton} from 'common-components-library'; // Not the real package name
import {makeStyles} from '@material-ui/core/styles';

const useStyles = makeStyles({
  loginButton: {
    backgroundColor: 'var(--color-white)',
    color: 'var(--color-orange)',
    border: 'none',
    '&:hover': {
      backgroundColor: 'var(--color-lightGray)',
      color: 'var(--color-orange)',
      border: 'none',
    },
  },
});

function Login() {
  const classes = useStyles();

  return (
        <BaseButton
          color="primary"
          onClick={doLogin}
          title="Sign In"
          variant="outlined"
          className={classes.loginButton}
        >
          SIGN IN
        </BaseButton>
  );
}

export default Login;

This way, my makeStyles from the main application will have a higher CSS priority than the makeStyles from my Common Components library.

So far, I have not found a way to control the order of makeStyles in the HTML head. I can control the position in the head for ALL Material-UI styles and makeStyles, but not individually.

I've tried using the injection order and injectFirst={true} but neither do what I need. Material UI Injection Order

Does anyone know how to do this? Or should I configure the two applications differently in order to rely on proper CSS specificity?

Here's a screenshot of the HTML head of the application that consumes the common components library. The (top to bottom) first makeStyles style tag is from the current main application. Which comes from the Login component code shown above. The second makeStyles style tag is from the Common Components library. Which comes from the BaseButton component code shown above. Which is NOT the order I want because the styles written in the Login component are overridden by the styles from BaseButton.

Image shows the order styles are injected into the HTML Head



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source