material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

Emotion Global component styles unexpectedly overridden by MUI styles (Next.js, TypeScript, Emotion Engine)

Open kevinpfox opened this issue 1 year ago • 3 comments

Duplicates

  • [x] I have searched the existing issues

Latest version

  • [X] I have tested the latest version

Steps to reproduce 🕹

Link to live example: https://github.com/kevinpfox/emotion-proof-of-concept-april

... is clone of - https://github.com/mui/material-ui/tree/master/examples/material-next-ts with as minimal changes as possible to demonstrate the issue.

Current behavior 😯

3px pink border does not render on <Button> component on this page: pages/about.tsx

actual-behavior

border style set here https://github.com/kevinpfox/emotion-proof-of-concept-april/blob/main/pages/about.tsx#L12-L27

Expected behavior 🤔

3px pink border renders on <Button> component.

Border provided by Emotion <Global> component in JSX of pages/about.tsx

expected-behavior

Expected DOM (something like this) (I manually pushed Emotion Global produced tag down the document DOM in Chrome dev tools)

expected-DOM

Similar to what we had previously with MUI V4

similar-to-our-production-v4-implementation

Suggested fix from MUI documentation to use prepend: true in createCache from import createCache from '@emotion/cache';

That code is in example and doesn't fix issue https://github.com/kevinpfox/emotion-proof-of-concept-april/blob/main/src/createEmotionCache.ts#L18

Context 🔦

Reason it matters: We would like to use Emotion <Global> to set all our custom overrides of MUI styles.

This is how we handled it with our current MUI V4 implementation - https://www.babycenter.com

We are switch from MUI V4 to MUI V5 and switching from styled-components to Emotion.

This has become a sticking point, since <StyledEngineProvider injectFirst> got the desired result with styled-components + MUI V4 setup, but we can not use that context with our upcoming Emotion + MUI V5 setup.

Side note: The following is a branch of the same demo above, with only difference being addition of <StyledEngineProvider injectFirst> Everything works great, just the way we want it, but there is the ominous hydration error, making it a no go.

https://github.com/kevinpfox/emotion-proof-of-concept-april/pull/1/files

why-we-cant-use-old-method

Your environment 🌎

kevinpfox avatar Apr 29 '23 18:04 kevinpfox

I worked around this issue by moving/converting all of our old MUI global overrides from a Emotion Global template literal style CSS block (was previously a styled-components Global template literal in MUI V4 version) ...and now all those override items are in a MUI createTheme block (as in import { createTheme } from '@mui/material/styles';) employing these sort of overrides....

components: {
  MuiButton: {
    styleOverrides: {
      root: { padding: 0 },
    },
  },
},

Which is probably the way the MUI team imagined it being done in the first place.

Two years ago we ran into issues using the V4 official override way (import { createTheme } from '@material-ui/core/styles';), so I choose to override the MUI selectors with a styled-components ThemeProvider template literal block, which worked great, back then.

Might be worth fixing the bug in case other devs have that situation. I get the feeling the MUI team want all of the MUI classes to be easily overridden from anywhere, even from non-MUI Global themes? (not sure). It took awhile to convert the template literal style CSS to the MUI createTheme JavaScript object style CSS since we have a fairly large codebase.

kevinpfox avatar May 01 '23 19:05 kevinpfox

@kevinpfox Thanks for reporting this, I'll check it out (that hydration error should be fixable)

Would you mind updating the package.json in your repro with more specific versions? Our templates all use latest, just in case something doesn't match with your actual app 🙂

mj12albert avatar May 02 '23 11:05 mj12albert

Thank you for checking it out.

Is <StyledEngineProvider injectFirst> still a legit solution? For some reason I got the sense it was retired solution. I may have gotten confused though. So many changes from V4 to V5.

I just re-read this https://mui.com/material-ui/guides/interoperability/#css-injection-order and it looks like perhaps it is still a legitimate solution.

I updated the packages to the specific versions I'm working on now.... https://github.com/kevinpfox/emotion-proof-of-concept-april/commit/c1b00b0c9d76963dc238e24946940d0af9b999ca

kevinpfox avatar May 02 '23 19:05 kevinpfox

I tracked back my confusion around these two.... @mui/styles/ vs @mui/material/styles

It's still not crystal clear to me what is and isn't deprecated.

I just stumbled upon this code comment I wrote in our codebase awhile back....

ss0

And then looked up this page (https://mui.com/system/styles/basics/)....

ss1

And now I'm staring at this branch of the demo project shared earlier (causes hydration issue)...

https://github.com/kevinpfox/emotion-proof-of-concept-april/pull/1/files

.... and it's becomes pretty apparent how one could get confused about what is and isn't an valid solution currently with MUI5.

I get that StylesProvider is not the same as StyledEngineProvider and they come from different imports. But it's pretty easy to see how one could get confused and have uncertainty.

Is the following a potential valid solution (once hydration issue is fixed)? <StyledEngineProvider injectFirst>

kevinpfox avatar May 05 '23 13:05 kevinpfox

Thanks for the detailed comments. To give some context:

  • @mui/styles in the legacy, JSS based styling solution. We are not recommending it since v5 - it is not compatible with concurrent rendering, and it will add additional bundle, as it is not based on emotion.
  • the <Global /> is intended to use for presets mainly. It will be inserted as first in the head - before any other MUI related styles, so that the component's defined styles will override the preset styles - this is why it is not working in your case. There are some workarounds around this, for e.g. you can use a global selector and bump the specificity of everything defined in your Global styles, however the theme overrides, using styled() and the sx prop will likely scale better.

Thanks @mj12albert for looking into the class name mismatch.

mnajdova avatar May 08 '23 10:05 mnajdova