material-ui: [system] unstable_classNameGenerator does not support multiple scopes

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

I am migrating to MUI v5 and I found some issues with styles collisions. On our projects, we use a micro front-end structure. That is, we have a Shell application and several micro-frontends which consume a custom library with differents components (like a custom table, custom breadcrumb, dropdown, etc.). This library that is consumed by all the micro frontends and shell is created with Storybook.

Before this migration, our collision issues were fixed with createGenerateClassName. On each micro-frontend, we used to have at the root this declaration:


const microfrontOne = createGenerateClassName({
  seed: "microfrontOne ",
});

...

return (
     <StylesProvider generateClassName={microfrontOne }>
       ....
     </StylesProvider>

Also, on our custom library, we used to have the same stylesProvider tag to make each component have its own name:

const sidebar = createGenerateClassName({
  seed: "sidebar",
});

export const SideBar: React.FC= () => {
    <StylesProvider generateClassName={sidebar}>
       ...
    </StylesProvider>

In this way, the styles of each component were correctly set and there was no chance to overlap.

image

All the microsites and the Shell imports Material FROM the library, so they all have the same version.

With the new library upgrade, the createGenerateClassName was deprecated so this behavior was no longer possible. I tried with unstable_classNameGenerator because I don’t find a better solution (TBH I don’t like to use something that has unstable on its name), but this does not work on the library with Storybook. As I already mention, I need to custom EACH component that I have in order to avoid styles collision. As the unstable_classNameGenerator is designed to be global, this does not work for me.

I can’t provide reproduction to this issue because there are several projects involved, but basically, I think that the issue is that I can’t provide specific tags for a specific component. I can bring more information if it is needed, please let me know. I really want this to be fixed because if it is not, I can’t use the new version of Material UI anymore.

Expected behavior 🤔

Have a way to give a custom tag to a React Component (not global to the app)

Steps to reproduce 🕹

No response

Context 🔦

No response

Your environment 🌎

No response

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 2
  • Comments: 23 (14 by maintainers)

Most upvoted comments

The solution to the initial question is here https://github.com/mui/material-ui/issues/29856#issuecomment-981855337.

From my perspective:

  • @mui/styles (JSS v5) @material-ui/styles (JSS v4): classNameGenerator was introduced to solve a style class names conflict problem. It can also be used to personalize your brand.
  • @mui/styled-engine: unstable_classNameGenerator is about personalizing your brand. To work, it needs to be a singleton, that has a called before any of the components are imported. It’s unstable because we are not sure poeple need to customize the brand in the first place.

I see two opportunities for improvements:

  1. https://mui.com/material-ui/experimental-api/classname-generator/ move to MUI System. It’s not about Material UI specifically.
  2. Document the purpose of the function more clearly.

Lastly, this means that @BiancaArtola will face the issue if you want to migrate JSS (@mui/styles) to emotion | styled-components. cc @oliviertassinari

@siriwatknp I would expect no issues. I believe it’s only a problem with @mui/styles because there are two elements with the .jss21 class name on the DOM. This is because JSS uses a class name counter, so the apps need to be configured so two counters don’t conflict. But with emotion, it’s a hash-based class name, so it only colid if the styles are identical, not if the style rule index is the same (1, 2, 3, … 21, etc.). In any case, a reproduction will tell us this for sure.

@oliviertassinari thanks for pointing this out. This is a note to @BiancaArtola for clarity, @mui/styles v5 is exactly the same engine (JSS) that you are using in v4, however in @mui/material v5 we have changed the default engine from JSS to emotion so the styles generated when you render a component is by emotion (there is a way to change to styled-components).

From what I read in the discussion above, you still need to use @mui/styles for style customization. I hope this helps.

Lastly, this means that @BiancaArtola will face the issue if you want to migrate JSS (@mui/styles) to emotion | styled-components. cc @oliviertassinari

But in v4 I used createGenerateClassName to fix this issue and it’s no longer present

@BiancaArtola You should still be able to import createGenerateClassName from @mui/styles. We only removed it from @mui/material.

@mnajdova Here is my idea to fix this issue.

Problem

image

Solution

Create react context for ClassName so that it can create a scope for each part of the application and communicate with the components under those trees. The components need to use the hook to get the class name generator function and use it via ownerState.generateClassName. However, the theming part won’t be able to use componentClasses.

createTheme({
  components: {
    MuiAutocomplete: {
      styleOverrides: {
        root: {
          [`& .${inputClasses.root}]: { // This does not work with a specific scope
          }
        }
      }
    }
  }
})

Since createTheme can be called anywhere, this is the developer’s responsibility to handle the class name styling.

This is my POC branch: https://github.com/mui-org/material-ui/compare/master...siriwatknp:fix/multi-class-name-gen

const fooGenerator = (componentName) => `foo-${componentName}`;

const barGenerator = (componentName) => `bar-${componentName}`;

function Playground() {
  return (
    <Box sx={{ display: 'flex', gap: 3 }}>
      <ClassNameProvider generator={fooGenerator}>
        <Button variant="contained">Foo</Button>
      </ClassNameProvider>
      <ClassNameProvider generator={barGenerator}>
        <Button variant="contained">Bar</Button>
      </ClassNameProvider>
    </Box>
  );
}
Screen Shot 2564-11-24 at 21 53 26

Hi. Thanks for creating the issue. Can you create a codesandbox that directly shows the error? You can fork this template: https://codesandbox.io/s/mui-issue-latest-s2dsx