Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can StylesProvider context be nested?

Is it possible to nest StylesProvider contexts, just like how we can nest ThemeProvider contexts?

I need a subsection of my app to use specific className prefixes in order to avoid className conflicts caused by hydration issues (out of my control). Unfortunately, the createGenerateClassName function attached to the more deeply nested StylesProvider isn't applying the specified productionPrefix to any of its children! Every className in the app is still prefixed with the default "jss" string.

If nested StylesProvider contexts aren't directly supported by MUI, is there a feasible/simple workaround?

like image 824
Reilly Bova Avatar asked Aug 08 '26 22:08

Reilly Bova


1 Answers

Below is an example using nested StylesProvider elements. I recommend using the seed option instead of the productionPrefix option, since the seed option is more explicitly for the purpose of avoiding class name collisions. The seed option is also in effect for both development and production mode whereas the productionPrefix option only affects production mode.

From https://material-ui.com/styles/api/#creategenerateclassname-options-class-name-generator:

options.seed (String [optional]): Defaults to ''. The string used to uniquely identify the generator. It can be used to avoid class name collisions when using multiple generators in the same document.

The nested StylesProvider does work, but with a caveat. The useStyles hook returned by makeStyles (if using withStyles, this still applies since it delegates its work to makeStyles) has logic that caches the style sheet generated for a particular component. So if you use a component both inside and outside the nested StylesProvider (e.g. MainAndSub in my example), it will use the first generated style sheet and not create new classes using the nested class name generator. This is generally a good thing, but it could confuse your testing/verification if you aren't aware of it.

import React from "react";
import {
  makeStyles,
  StylesProvider,
  createGenerateClassName
} from "@material-ui/core/styles";

const generateClassNameMain = createGenerateClassName({ seed: "main" });
const generateClassNameSub = createGenerateClassName({ seed: "sub" });

const useMainStyles = makeStyles({
  mainTree: {
    backgroundColor: "blue",
    color: "white"
  }
});
const useSubStyles = makeStyles({
  subTree: {
    backgroundColor: "green",
    color: "white"
  }
});
const useMainAndSubStyles = makeStyles({
  mainAndSub: {
    backgroundColor: "red",
    color: "white"
  }
});
const MainAndSub = () => {
  const classes = useMainAndSubStyles();
  return (
    <div className={classes.mainAndSub}>
      MainAndSub className: {classes.mainAndSub}
    </div>
  );
};
const MainTree = () => {
  const classes = useMainStyles();
  return (
    <>
      <div className={classes.mainTree}>
        MainTree className: {classes.mainTree}
      </div>
      <MainAndSub />
      <StylesProvider generateClassName={generateClassNameSub}>
        <SubTree />
        <MainAndSub />
      </StylesProvider>
    </>
  );
};
const SubTree = () => {
  const classes = useSubStyles();
  return (
    <div className={classes.subTree}>SubTree className: {classes.subTree}</div>
  );
};

export default function App() {
  return (
    <div className="App">
      <StylesProvider generateClassName={generateClassNameMain}>
        <MainTree />
      </StylesProvider>
    </div>
  );
}

Edit Nested StylesProvider

like image 108
Ryan Cogswell Avatar answered Aug 10 '26 13:08

Ryan Cogswell