How to use Material UI from component library in a project with Material UI already?

Viewed 1047

I'm using Material UI in my project and at same time, we have a component library (a npm package with many shared React components).

These components in the library are also based on Material UI.

So when I import these components from library to use in my project, it's duplicating the <styles> block to some component that're in use (for example MuiButtonBase-root).

Based on this, it's reseting some css styles, when the second MuiButtonBase-root come after.

Is there a solution for this?


Edit 1:

Here's an example, maybe components are not in this order, because I'm not really sure in which order the issue happen.

// myProject
import { AppBar, Tabs, Tab, ThemeProvider } from '@material-ui/core';
import { Button, SharedComponentProvider } from '@shared-components'; // components based on MUI

function App() {
  return (
    <SharedComponentProvider>
      <ThemeProvider theme={fooTheme}>
        <AppBar position="static">
          <Tabs>
            <Tab label="Item One"  />
            <Tab label="Item Two"  />
            <Tab label="Item Three"  />
          </Tabs>
        </AppBar>

        <Button>Click me</Button>
      </ThemeProvider>
    </SharedComponentProvider>
  );
}

The SharedComponentProvider is like this:

import { StylesProvider, createGenerateClassName } from '@material-ui/core/styles';
const generateClassName = createGenerateClassName({
  seed: 'shared-components',
});

function SharedComponentProvider({ children }: any) {
  return (
    <ThemeProvider theme={sharedTheme}>
      { children }
    </ThemeProvider>
  );
}

Since Tab component is also based on MUI Button component, so it will create two tags of <style> with . MuiButtonBase-root inside, which can end up in this case.

3 Answers

Tonight I've had the same problem in MUI 5.x. and solved it by a litte library-component called ThemeInheritor.

import React from "react";
import { Theme, ThemeProvider} from "@mui/material/styles";

export interface ThemeInheritorProps  {
  theme: Theme;
  children: React.ReactNode
};

export default function ThemeInheritor({ theme, children }: ThemeInheritorProps) {
  return (
      <ThemeProvider theme={theme}>
          {children}
      </ThemeProvider>
  );
}

It just gets the theme of the application an provides it to the library 'world'.

After exporting this component to your application it should be integrated in the theming process at the head of the appliction like this:

import { ThemeInheritor } from "YOURLIBRARY";

...

<StyledEngineProvider injectFirst>
  <ThemeProvider theme={muiTheme}>
    <ThemeInheritor theme={muiTheme}>
    ...
    </ThemeInheritor>
  </ThemeProvider>
</StyledEngineProvider>

Where muiTheme is the theme created by the createTheme() function.

The ThemeInheritor provides the theme of the hosting application to all library components used in the tree.

You are exporting Button and SharedComponentProvider components from the @shared-components package. You also need to export ThemeProvider from the @shared-components package.

This is because in your @shared-components package, you are wrapping your components with Material UI's ThemeProvider. You need to reuse the same provider inside your main application.

import { AppBar, Tabs, Tab, ThemeProvider } from '@shared-components';
Related