material-ui: [v5] CSS injection order is wrong
I’m using the following pattern in my code, but it doesn’t work anymore in v5 (tested with 5.0.0-alpha.20). My custom styles get overwritten by other styles (likely coming from the new styling mechanism):
const styles = theme => ({
title: {
[theme.breakpoints.down('sm')]: theme.typography.body1
}
})
function App({ classes }) {
return <Typography variant="h5" classes={{h5:classes.title}}>Hello</Typography>;
}
const StyledApp = withStyles(styles)(App);
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 24
- Comments: 59 (35 by maintainers)
I was aware of
injectFirstattribute, but it didn’t work in my app. After some testing with the codesandbox, it appears the problem come from importingStylesProviderfrom@material-ui/core/styles(v4 code, which I’m currently migrating) instead of@material-ui/core. You can verify that in your codesandbox.@goffioul now that the Typography, Button, etc components are migrated to emotion, you need to use the
StylesProviderexported from ‘@material-ui/core’ with theinjectFirstoption, in order for the CSS injection order to be correct between emotion and JSS. It is explained here: https://next.material-ui.com/guides/interoperability/#css-injection-order.This is only required for the time of the migration (v5-alpha phase). Once we do no longer depend on JSS, the order should be correct.
Here is a codesandbox with a working example - https://codesandbox.io/s/devtools-material-demo-forked-ethyg?file=/index.js You will notice that the
<Demo />is wrapped with theStylesProvidercomponent.Hi guys, I am trying to figure this out, using Styled Components, any tips? It works ok during SSR, but during the client rehydratation, I have JSS style tags that resets my button style, removing their background.
My current setup is basically like this:
I use both
makeStylesand Styled Components during this v4 to v5 transition phase.I fail to understand what is expected. It seems to me that
StyledEnginewill manage my v5 styles, andStylesProvidermy v4 legacy styles, so I get it I might need a combination of both to get the right order. But I cannot find the right setup.This one seems to put Styled Components upper in the tree, but that’s JSS I want to move up.
Also tried this one:
Part of the styles are indeed upper, but not all of them! One of them in particular is resetting my button with a transparent background, as if it was some kind of default style coming from the theme. I don’t get how to force to get upper in the tree, injectFirst doesn’t have any effect.
Just to make it clearer, here are my imports:
Sorry for the lack of reproduction, this is a real-life setup. Basically half the JSS styles don’t resepect
injectFirst.Update: I am running a few more experiments today. Using a custom
insertionPointin my JSS config will get my styles back together, but still not at the right place (injected after Styled Components, and not before).It seems that what I want is just
StylesEngine injectFirst, to move JSS up in the head. I don’t needStyledEngineProviderbecause Styled Components is ok.This issue seems to boil down to
jssnot respecting the insertion point for core Material UI elements.injectFirstis behaving as expected, but only half the JSS styles are respecting the generated insertion point. I’ve tried to add manuallty the<!--mui-inject-first-->comment so it’s there even during SSR, in case it was an issue with the insertion point not being present at the right time, but no luck. This seems to affect the styles that are not server-rendered, maybe an instance of this issue? https://github.com/cssinjs/jss/issues/798My palliative in the meantime, that will move
data-jssupper at first render:New update: my JSS mover fixes some stylings… but breaks some others, as core Styled Components based styles are now overriding my own components. Basically, the JSS are kinda reversed: my custom styles are a the top, but the raw types are still at the bottom. I’ve updated it so it moves only the “Mui*” styles that seems to be the faulty one (the other have “makeStyles” as Meta and work correctly)
As a developer using material-ui (not developing it), initially I totally missed the different import. Using the same name obviously adds to the confusion, because old code is already importing
StylesProviderand you don’t realize you have to import it from another module to get a different implementation. It’s also not obvious that when migrating code that uses JSS, you actually need to use both providers to manage the import order properly (or is there a better alternative?). Yes, the doc says you need to useinjectFirstin yourStylesProvider, but it doesn’t tell you explicitly which one (in my case, I usedinjectFirston theStylesProviderI already imported in my code, but it was the old one, and that didn’t have the wanted effect).If the target is to have a drop-in replacement for the v4 styling engine, I’d say using the same name is a good option. The problem I’m having is just a transient situation in alpha-grade code, I can live with that. Maybe a warning when using the old StylesProvider would help detect such scenario. If a drop-in replacement is not on the table, then I’d go with a different name.
Wouldn’t be possible without a tip from @mnajdova - if you see styles coming from a “static” class name (like
MuiButtonBase-root) and if those styles are not under your control, but generated by JSS, then it’s most likely that it’s some rogue v4 in your codebase.The solution in https://github.com/mui-org/material-ui/issues/24109#issuecomment-750794821 worked for me. For others who might be lacking the
<StylesProvider/>, I’ll just note that one very salient phenomenon is that all components that were previously round (like Fab, DatePicker days, etc.) are rectangular (because theborder-radius: 0takes precedence). Just writing this down so that others can find this issue faster through GitHub search.@sep2 emotion doesn’t provide such capability, only styled-components does. The closest is https://emotion.sh/docs/@emotion/cache#prepend. I’m going to open an issue on emotion as I can’t find any duplicates.
Ah ok, I see the confusion now. The examples use custom emotion cache, which means that it is enough toa add
prepend: trueas an option and it would do the same as theStyledEngineProviderwithinjectFirstwould do. We have that as an explanation on the docs:Reference: https://mui.com/guides/interoperability/#main-content
If you want to use both emotion and JSS, you should configure and add the styles in the correct order for SSR, this is how we do it for our documentation: https://github.com/mui/material-ui/blob/master/docs/pages/_document.js
Why is use of
<StylesProvider injectFirst>not implemented in the NextJS MUI example docs?Starting a new app and wanted do things the “right” way instead of using deprecated JSS. However while using v5 with emotion we had to come here to learn about
<StylesProvider>to avoid littering our codebase with!importantOnce we added in this secret super power Component in _app.js our styles were finally applying correctly.
UPDATE: Didn’t realize it had changed from @material-ui to @mui. Double checked my deps in package.json and saw entries for @material-ui and @mui. Reinstalled with just @mui and updated import paths properly fixed this issue.
if you’re using
@mui/x-data-gridmake sure to use the peer dependency of@material-ui/coreversion^5.0.0-beta.0. For me, it was the last remaining legacy 4.x module that was inject jss.Found the issue was on my end. Apparently, the codemod missed some of the
imports (and there was a “rouge” peerDep for v4 (courtesy ofmdi-material-ui), allowing the import to almost work). Updating these to v5 imports resolved the issue I was having. Thanks so much @Andarist for pointing this out!Actually, there is already an issue with it: https://github.com/emotion-js/emotion/issues/2037.
@mnajdova We probably want to progressively remove
injectFirstfrom the documentation as we have migrated all the components to em/sc and are close for the docs as well.None of the solution above worked for me.theme override(styleOverrides) always take precedence of styling comes from makeStyles APIEdit: Nevermind, the injection order was correct(emotion styles comes first and then JSS), for me it was a specificity issue, somehow the styling logic of components from v5 has changed to have higher CSS specificity, so I had to increase CSS specificity of existing style key like below.
Somewhat rough solution for a very similar problem (from what I understand about
makeStyles): https://github.com/emotion-js/emotion/issues/1853#issuecomment-623349622This is intentionally not super easy to do as we encourage 0-config SSR to be used 😉
I’m not super sure how things will play out but the current 0-config SSR strategy (or something close to it) might be the base for handling server components. Some context here: https://github.com/reactjs/rfcs/pull/189#discussion_r548468803 . It’s, of course, not certain - I have not received any feedback there and some other solution might be figured out along the way.
@oliviertassinari any plans to add more to the docs regarding the styled/experimentalStyled hooks?
It’s actually a bit more complicated than that, and I actually need to use the 2 styles providers, like the following:
Thank you very much for the explanation, this helped a lot. I think I got confused with all the possibilities and namings. It’s much more clear now 😃
<StyledEngineProvider /> doesn’t work well with SSR if you are having issues with SSR and the emotion cache giving nothing (which may not be obvious) it’s because of the StyledEngineProvider.
On the other hand without StyledEngineProvider then non-SSR mechanism don’t work well.
There was nothing wrong with JSS, but emotion and JSS “DO NOT” play nice with each other.
I’ve even had situations where the render changes unexpectedly as if hitting some race conditions.
For anyone considering migrating to v5 if you are happy with v4 it’s not worth it. It’s been 2 weeks for me, and I think I have to rewrite everything to drop JSS because emotion and JSS refuse to work together, I’ve tried every trick in the book, it’s not reliable.
There hasn’t been any activity on the issue for over a month and a fix was provided for the initial issue. I am closing it.
As an exception - I can help you if you send me a replay of the problem privately and describe the issue you are facing in detail (both what happens and what is your expected result)
I’d be happy to share a recording provided it can be privatly
I couldnt recommend https://replay.io/ enough for debugging tricky cases
On my side I just solved it by finishing the upgrade process to completely get rid of JSS. I strongly suspect it was related to multiple instance of mui / having old versions etc. So very difficult to repro. Anyway that’s a temporary issue part of the migration process so no huge deal.
I couldn’t fix my issue with injection order, hover the migration path using
tss-reactis brilliant, it worked rather quickly. One thing missing in the doc though, is that when migration to v4, we should also be careful about migrating dependencies. It’s easy to forget that your app is somehow usingmaterial-ui-search-barfor some reason => it will unexpectedly load v4 into your app and you’ll havejssstyles despite having migrated everything. In this case, the dependency must also be migrated (opening a PR, getting rid of it, copying into your own code etc. will do the job). For instance,mdi-material-uiis in the proces of upgrading, but still using the old package name => you might want to wait a few week before triggering a migration if you strongly depend on it.Agree, I would wait until we migrate the demos to emotion as well, as there are still some JSS usages there 👍
@jcursoli In theory, it should be easy to implement the
withStylesAPI using theClassNameshelper of emotion. If you want to give it a try in codesandbox and share the result, it would be awesome.For
makeStyles, I doubt we can have an adapter. But maybe @Andarist would have an idea.I am facing similar issue with new fresh project & none of the suggested solution working for me.
themeconfiguration & custom styles are getting overridden by material default styles.I am using following versions:
@oliviertassinari @mnajdova Please assist. Thanks!
In this transition period, until we migrate all component to emotion, you cannot have both combinations (JSS components & emotion overrides & emotion components & JSS overrides, simply because in that case we don’t have predictable order of CSS injection we should expect). We recommend if you want to start early to adopt your overrides to use emotion to migrate it only on components which are already migrated to use emotion by default. You can track the progress here - https://github.com/mui-org/material-ui/issues/24405
Because emotion styles now have to be injected before JSS styles, emotion’s css prop can no longer be used to override styles of components that are still using JSS internally unless
!importantis used. It seems that the only solution is to migrate from emotion to JSS for those components, and only once MUI fully converts to emotion - migrate back. Is there a better way?@mainfraame Prefer using modules coming from
@material-ui/styled-engine(emotion/sc) and avoid modules from@material-ui/styles(JSS)