Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material-UI theme not working in shared-component

Tags:

material-ui

I'm building a reusable shared-component library using material-ui which is being imported in my main app like this:

import { theme, StepperComponent } from '@company/shared-components';
import { ThemeProvider } from '@mui/material/styles';

...

return (
  <ThemeProvider theme={theme}>
     <StepperComponent steps={stepperTitles} />
     ...
)

The stepper component is in my shared-components repository which I'm npm-linking

import React from 'react';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import { StyledStepper, StyledStepConnector, StyledStepIcon } from './Stepper.styles';

const StepperComponent = ({ steps, ...props }) => {
  return (
    <StyledStepper {...props} connector={<StyledStepConnector />} alternativeLabel>

However, for some reason the theme isn't getting applied to this component even though I'm wrapping it in the theme provider. When I log out the theme it doesn't include the colors that are in the theme being imported to my main app.

Does anyone know why this might be happening?

like image 970
MarksCode Avatar asked May 26 '26 00:05

MarksCode


2 Answers

I'm dealing with something similar and haven't resolved it completely, but I have a strong feeling it involves multiple React contexts being created inside material-ui and emotion/react.

The ThemeProvider only exposes the theme to the components that have access to its context - the components within your main application.

I was able to achieve the desired behavior by making sure material-ui's ThemeProvider and it's context lives in the shared component library and not the main application. I did this by exporting a simple wrapper of ThemeProvider from the component library; literally just:

interface LibraryThemeProviderProps {
  children?: React.ReactNode;
  theme: Theme;
}

const LibraryThemeProvider: React.FC<LibraryThemeProviderProps> = ({ children, theme }) => (
  <ThemeProvider theme={theme}>
    {children}
  </ThemeProvider>
)

and then using LibraryThemeProvider in the place of material's ThemeProvider in the main application.

If you want the same theme applied within your main application you only need to leave the original ThemeProvider in place alongside the new LibraryThemeProvider.

I'd prefer to solve this with a single ThemeProvider but haven't been able to yet :/

Note: I am using the useTheme hook inside all my components to access the theme. useTheme will use material's default theme if it doesn't see one provided by the ThemeProvider context - all this happens under the hood.

like image 172
Kaschman Avatar answered May 30 '26 22:05

Kaschman


I have encountered the same problem recently. There were likely two copies of @mui/material loaded simultaneously.

If we symlinked the @company/shared-components package into main-app directly, all the packages defined in "devDependencies" will be included even though we have included them in "peerDependencies." Thus, resulting in the following dependency tree.

main-app
└─ node_modules
   ├─ @mui/material <-- ThemeProvider in the main app will load this
   └─ @company/shared-components
      └─ node_modules
         └─ @mui/material <-- Components from shared-components will load this

In my case, the solution for Webpack is to include @mui/material in resolve.alias to mimic the notion of peer dependencies, which is to use the package installed in the main-app

resolve: {
  alias: {
    '@mui/material': 'node_modules/@mui/material'
  }
}

Related Questions

  1. MUI ThemeProvider is not injecting theme in a compiled component
  2. How to create a shared component library with MUI 5
like image 37
Yeoh Joer Avatar answered May 30 '26 23:05

Yeoh Joer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!