This RFC is a proposal for changing the styling solution of Material-UI in v5.
TL:DR; the core team proposes we go with emotion
Whatever styling engine we choose to go with we have to consider the following factors:
@material-ui/styles
has partial support as I'm writing.It would be nice if it can support the following:
Here are benchmarks with dynamic styles of several popular libraries (note the Material-UI v4 only use static styles which have good performance):
PR for reference: https://github.com/mnajdova/react-native-web/pull/1
Based on the performance, I think that we should eliminate: JSS (currently wrapped in @material-ui/styles), styletron, and fela. That would leave us with:
Based on the open issues, it seems that Aphrodite doesn't support dynamic props: https://github.com/Khan/aphrodite/issues/141
which in my opinion means that we should drop that one from our options too, leaving us with:
While styled-components
and emotion
are both libraries are pretty popular, react-styletron
at the time or writing is much behind with around 12500 downloads per week (this in my opinion is a strong reason why we should eliminate it, as if we decide to go with it, the community will again need to have two different styling engine in their apps).
Here is the list rang by the number of Weekly downloads at the time of writing:
Note that storybook has a dependency on emotion. It significantly skews the stats.
SimilarWeb estimated sessions/month:
Based on the survey, 53.8% percent are using the Material-UI styles (JSS), which is not a surprise as it is the engine coming from Material-UI. However, we can see that 20.4% percent are already using styled-components, which is a big number considering that we don't have direct support for it. Emotion is used by around 1.9% percent of the developers currently based on the survey.
Having these numbers we want to push with better support for styled-components, so this is something we should consider.
Even if we decide to support multiple engines, we would still need to advocate for one by default and have one documented in the demos.
styled
API, which means for developers they will always have wrapper components if they need to re-style.We may try to support multiple CSS-in-JS solutions, by providing our in house adapters for them. Some things that we need to consider is that, that we may have duplicate work on the styles, as the syntax is different between them (at least jss compared to styled-components/emotion). We will reuse the theme object no matter what solution we will pick up.
The less involved support for this may come from the usage of the styled
, as people may do some webpack config to decide which one to use - (this is just something to consider).
Regarding how the classes look and how developers may target them, I want to show a comparison of what we currently have and how the problem can be solved with the new approach.
As an example, I will take the Slider component. Here is currently how the generated DOM look like:
Each of the classes has a very well descriptive semantic and people can use these classes for overriding the styles of the component.
On the other hand, emotion, styled-components or any other similar library will create some hash as a class name. For us to solve this and offer the developers the same functionality for targeting classes, each of the components will add classes that can be targeted by the developers based on the props.
This would mean that apart from the classes generated by emotion, each component will still have the classes that we had previously, like MuiSlider-root
& MuiSlider-colorPrimary
, the only difference would be that this classes will now be used purely as selectors, rather than defining the styles for the components. This could be implemented like a hook - useSliderClasses
No matter which solution we would choose, we would use the styled
API, which is supported by the two of them. This will allow us down the road to have easier support for styled + unstyled components (probably with webpack aliases, like for using preact).
After we investigated the two options we had in the end, the core team proposes we go with emotion. Some key elements:
Developers already using styled-components should be able to use emotion with almost no effort.
The support of cx + css from emotion can be beneficial for developers to use it as an alternative for adding style overrides if they don't want to create wrapper components.
Kudos to @ryancogswell for doing a deeper investigation on this topic. So far we did not find anything in @emotion's code that would give us concern that concurrent mode wouldn't work.
We were also looking into createGlobalStyle
from styled-components as a comparison to emotion's Global component. It is doing most of its work during render (inherently problematic for Strict/Concurrent Mode) and just using useEffect for removing styles in its cleanup function. createGlobalStyle needs a complete rewrite before it will be usable in concurrent mode -- it isn't OK for it to add styles during render if that render is never committed. It looks like someone has tried rewriting it with some further changes in the last month, so we will need to follow this progress.
Emotion's docs recommend doing composition of CSS into a single class rather than trying to leverage styles from multiple class names. In v5, our existing global class names would be applied without any styles attached to them. The composition of emotion-styled components automatically combines the styles into a single class. This potentially gets rid of these stylesheet order issues at least internal to the styles defined by Material-UI, because every component's styles are driven by a single class name :+1:.
So we would have the global class names (for developers to target in various ways for customizations) and then a single generated (by emotion) class name per element that would consolidate all the CSS sources flowing into it.
Specificity is then handled by emotion based on the order of composition.
All compositions using emotion (whether render-time or definition-time composition) results in a single class on the element.
styled-components does NOT work this way concerning render-time composition (definition-time composition does get combined into a single class). The same composition in styled-components results in multiple classes applied to the same element and the specificity does not work as I would have intended.
What do you think about it?
Just to a couple of corrections:
The React community, at large, has voted against using JSS at scale.
I would suggest instead that the React community didn't vote _for_ JSS. Perhaps it wasn't "marketed" as well as other solutions?
We didn't bet on the right horse.
We bet on the only horse โ it was a one-horse race. None of the other solutions available at the time ticked all the boxes.
Emotion sounds great! I love getting TS support, e.g., autocomplete and all the benefits of typing - with CSS-in-JS - when building UI or styling components, will that still be possible? How is this going to affect that, if at all? TS support is apparently better, amazing!
The last bit got me! I'd love helping by doing this behind a beta flag or develop on some features:
All compositions using emotion (whether render-time or definition-time composition) results in a single class on the element.
Styled-components do NOT work this way concerning render-time composition (definition-time composition does get combined into a single class).
I also noted that the theme object is going to stay the same, the - in my opinion - the absolute best way to theme an application! I have nothing else to say :astonished:
Thanks for the great work on M-UI. I love the direction the project is going.
Moving to a more standardized way of styling is the way to go. I know the team and community will work out the kinks, and v5 - by the sounds of it - is going to be even more awesome! :rocket:
As someone who has used both styled-components and emotion I can confirm transitioning between them is easy and painless.
+ emotion is more typescript friendly
Speaking as Emotion's maintainer - this sounds great ๐
We should also be able to release a new major soon-ish which won't be any revolution, just some cleanups, overall improvements, hooks under the hood and TS types improvements (better inference and performance).
Oh, and rewritten parser! that eliminates some edge bugs in Emotion and Styled-Components (as currently, they are both using the same parser). It is both smaller and faster.
What about breaking changes, which option introduce more breaking changes (if any)?
Not sure if it makes a difference but were the benchmarks done with emotion and/or style-component's babel plugins? They help to optimize things further.
It was my understanding that MUI had previously indicated it was going with styled so this is a surprise. I think emotion is a great library, but with more people using styled currently it's important you find ways to give them good options if they don't want to migrate to emotion
@ee0pdt Emotion is very, very much like styled. I think that's part of the whole choice for Emotion over styled-components. There are clear benefits, and migration debt is little to none.
And there's a whole section about supporting both by giving a choice to developers. That could be a way to go, but then again, standardizing would probably help future us more. The full concurrency and no wrapper components is a deal-breaker for me. I get that others might want something styled provides, and that should be considered. I'd rather push toward standardization
Why was styletron-react ruled out? It leaves out a whole metric that wasn't considered, which is memory consumption. The default styletron engine (and fela) is atomic. Whilst a bit slower it saves a lot of memory. Having seen a lot of react pages do nothing and go >1GB after a while it's a bit of a concern. The browser freezes after that.
With an atomic framework performance improves over time globally, across components as each atomic "class" is cached. Likely not reflected in the test either.
Happy with either as long as it supports SSR
I just withdrew my vote from the original styled components issue :sweat_smile: - first learned to know emotion through storybook, but It will mean that all components styles need to be created using the styled API, which means for developers they will always have wrapper components if they need to re-style.
got me to switch.
Thanks everyone for the quick feedback. Here are answers to some of the comments/questions.
What about breaking changes, which option introduce more breaking changes (if any)?
@sag1v using styled-components
vs emotion
does not introduce any more or less breaking changes that we will need to handle. The overall breaking changes would be around how the overrides inside the theme would look like:
// previosly
root: {
contained: {
'&$disabled': { // <-- this part will need to be transformed
color: 'red',
},
},
containedPrimary: {
color: 'blue',
},
}
// after
root: {
contained: {
'&.Mui-disabled': {
color: 'red',
},
},
}
However as the styles syntax between emotion
& styled-components
is identical, it won't make any difference.
Not sure if it makes a difference but were the benchmarks done with emotion and/or style-component's babel plugins? They help to optimize things further.
@hc-codersatlas nope, but the perfs are those are anyway between the top few, so I don't believe it would make any difference. Good call tough!
Why was styletron-react ruled out? It leaves out a whole metric that wasn't considered, which is memory consumption. The default styletron engine (and fela) is atomic. Whilst a bit slower it saves a lot of memory. Having seen a lot of react pages do nothing and go >1GB after a while it's a bit of a concern. The browser freezes after that.
With an atomic framework performance improves over time globally, across components as each atomic "class" is cached. Likely not reflected in the test either.
My comments around why styletron-react
was ruled out may be a bit misleading sorry about that, will update the PR description rightaway. The perf are good, but the biggest concern I have with styletron is the community: https://www.npmtrends.com/styletron-react-vs-@emotion/core-vs-styled-components While both emotion and styled-components are over 2000000 downloads in the last 6 months, styletron is around 15000.
Also atomic css may cause issues with overrides, as each classname contains only one styler rule.
I have got a question if we decide using emotion we want to add below code on top of all files?
/** @jsx jsx */
This is JSX pragma, by default JSX pragma is React.createElement
You need to add it if you are using the css
property in emotion. For the styled
API as well as the regular className API you don't need it.
It is possible to skip adding JSX pragma, but it requires extra Babel setup and it comes with worse support from the tooling - for example, TS is not able to type-check your CSS prop as accurately as it does when using JSX pragma. More information can be found here: https://github.com/emotion-js/emotion/pull/1941/files#diff-9abe25e5d2b00958d4b9849f5f20c139R5
@mnajdova thanks. I was just hoping memory usage is covered more than vouching for styletron in particular. As to downloads or community - "only" Uber uses styletron :) so no worries. Voted for emotion in the first place.
Would be cool if there was a babel plugin or similar that can transform static styles to real css classes. There's already a similar library called compiled
. Most styles realistically are static.
To be useful Fela will require a set of plugins like fela-plugin-rtl
, fela-plugin-prefixer
which will make performance even worse (https://github.com/microsoft/fluentui/pull/12289) ๐ข And then you will probably end up with Emotion (https://github.com/microsoft/fluentui/pull/13547) as sometimes it can be twice faster than Fela ๐ฆ
My only concern is having to use css
thingy from Emotion. That is a big red-flag based on my experience. I had to remove such thing from a large codebase and wasn't fun. Why? Because it is an abstraction that brings more problems than the one that solves in the long term.
Most of the time, we try to use styled
function, but we are quite happy with makeStyles
function for generating some classes in some cases.
Hopefully, there is no breaking change for those two APIs, and the I am not forced to use css
macro.
My only concern is having to use css thingy from Emotion.
@yordis You definitely won't be forced to use the css
prop. I suspect there will be some degree of change for usages of makeStyles
and withStyles
. Hopefully the amount of change necessary can be mostly limited to a codemod on the imports. I don't think the approach used in makeStyles
or withStyles
will be practical to support using emotion, so I would expect any ongoing support of those APIs to be through a separate package (so that "@material-ui/core" no longer has a JSS dependency) which would probably receive only minimal maintenance after v5 is released (the details around what happens to makeStyles
and withStyles
aren't nailed down yet, so this is just my speculation about the implications of moving forward with emotion).
๐ the choice to use Emotion. Avoiding the styled
API of styled-components
is one reason my team chose Emotion (which also supports a similar styled
API in addition to the css
prop). We presently use Emotion for Material UI style customization and it works pretty well. Built in support would just be icing on the cake.
Regarding these facts:
Many developers use styled-components to override Material-UI's styles. End-users find themselves with two CSS-in-JS libraries in their bundle
Support concurrent mode
styled-components: Partial
If styled-components had full support for concurrent mode, would it be a more sensible choice, given most developers are overriding MUI with styled-components (excluding JSS)? The point about emotion being smaller in bundle size is moot if 2 css-in-js solutions need to be included. And I would presume most practical applications of MUI involve overriding its styles.
Where I and my team use Emotion as a main way of styling components, I came across some inefficiencies present in emotion library. And I wonder what you guys think about these inefficiencies explained below.
Consider below Emotion StyledComponent;
const StyledComponent = styled.div`
${({color}) => color && `color: ${color}`};
display: flex;
justify-content: center;
align-items: center;
background: teal;
font-size: 20px;
padding-top: 8px;
padding-bottom: 8px;
margin-top: 12px;
margin-bottom: 12px;
border: 1px solid grey;
`
When color prop changes new css class is generated with all css props (display: flex, justify-content, ..., border: 1px soild grey
) copied over. Which would result in css classes with the exact same css props for each color prop, see below;
Another inefficiency we have found is when a new component is derived from above StyledComponent
it will create a new class with all the css props copied over from base StyledComponent
. Consider below;
const DerivedComponent = styled(StyledComponent)`
font-family: monospace;
`
It creates another css class that only adds font-family: monospace
to the above css class generated from StyledComponent
. That is, It creates a css that has all the props copied over from StyledComponent
as can be seen below;
Now if above StyledComponent
and DerivedComponent
are used together we (initially) have two css classes which have duplicate css props, (differing only in font-family). As can be seen below;
As you can imagine a number of css classes that have duplicate css props of each other can grow quite quickly.
I found that with Emotion, as component styles are composed together, we end up with css classes with many duplicate css props.
I am not sure this duplicate of css props in each css class has any noticeable impact on apps, but I wonder if this is taken into account on choosing to use emotion.
I am not questioning the performance of Emotion in creating and applying CSSStyle at run time. Emotion is one of the fastest on applying CSSstyles as evident in perf tests.
I am just concerned resulting CSSstyle is bloated. And as Emotion can be SSR(ed) which means styles are inlined in HTML, we just might get unnecessarily bloated (with css style tags) HTML file. Which in turn results in lot more tags to parse with unnecessary css props by browsers.
If styled-components had full support for concurrent mode, would it be a more sensible choice, given most developers are overriding MUI with styled-components (excluding JSS)? The point about emotion being smaller in bundle size is moot if 2 css-in-js solutions need to be included. And I would presume most practical applications of MUI involve overriding its styles.
@petermikitsh the reasons why we concluded on emotion are actually the four points in the conclusion
Having the first point in mind, if developers really want to avoid having two css-in-js solutions in the bundle, the migration cost is really small for moving to emotion + it supports different API other than the styled
.
@ko-toss thanks for writing this up these are all good points. The fact that emotion generates one className with all styles, makes it the better engine for resolving overrides. The problem we may have with generated multiple classNames is that the last class written will win, which may become problematic in the future.
On another project, I was using atomic css, where from memory consumption is much better because all css rules are written only once, but doing predictable overrides there is pretty hard, as each className is one atomic rule, and than again which one wins, depends on the order of which they are written, if you do not decide to previously process all styles and merge them correctly, which may impact perf in the end.
On the other hand, I believe that using any css-in-js solution, people will not just randomly create infinite combination of styles, they are still pretty structured based on the props value.
However, again these are good points, that we will have in mind, thanks a lot for sharing them ๐
- else?
what about [stylex] idea compatibility (like [style9])
(this is rather FYI, emotion is a good choice)
https://github.com/cristianbote/goober (1kB, perf little worse than emotion)
I have no experience with that yet but I want to try it one day.
@cztomsik Similar to https://github.com/kuldeepkeshwar/filbert-js but has no JavaScript syntax support (only CSS template string)
Here are some tests done with google lighthouse on time-to-interaction time:
FYI, I've done some detailed benchmark of styled-components v5, emotion v10, and emotion v11, with/without babel plugin, with vanilla API, css props API, and styled API. Hope this help the discussion!
Did you consider the new wave of css-in-js libraries that rely heavily on atomic css and typescript support?
Did you consider the new wave of css-in-js libraries that rely heavily on atomic css and typescript support?
It's not on the benchmark, but currently otion is 2~4 times slower than emotion. I think otion indeed have pretty big potential and believe there is a room for the optimization, but otion is not really ready for the production yet.
I didn't test the stitches yet, though. ๐
What about an actual zero-runtime library? I haven't seen anyone mention linaria.
I stumbled across linaria at some point and I really like it. My only worry with is that the dynamics props styles solely depend on css variables, and there isn't any support for IE 11 based on https://github.com/callstack/linaria/issues/445 Also compared to styled-components
and emotion
the community is much smaller at this moment.
@TheHolyWaffle
Linaria is awesome.
Iff you set it up properly, I believe it is the best of both css-in-js (in terms of dev experience), and pure css (can't beat pure css performance). It even optimizes(dedupes) and reuses css rules.
But linaria requires build and bundling step which would be hard for beginners.
I would love to see ports for other css-in-js libraries with similar API surface e.g filbert-js /goober
@kuldeepkeshwar We will let you know once we look into the adapters for the styled API :)
How does https://compiledcssinjs.com/ fit into all of this? It seems to be an incredibly interesting approach; Compiled also runs RFCs for the project, which proves to be great for open source and collaboration. _wink wink_
I think the future is very, very bright for styling the web, and I hope Material-UI will be an integral part of the go-to solution for styling any app.
The explanation of how Compiled works got to me:
This kind of transformation allows us to deliver your component to any consumer without needing them to configure/setup their tooling. Just import and go. This is powerful, and more importantly, the same as current CSS in JS libraries work - with one catch.
_CSS can't be generated at runtime._
This single constraint opens a lot of doors for us. Build time optimizations. Runtime guarantees. Performance bottlenecks gone.
On a different side note, I'd like to point out that popularity doesn't mean much for a good project. I love MUI and the work that has gone into it thus far; I also think it is fantastic it has become a premium product.
But choosing a 'popular' _name_ for the sake of popularity isn't a reasonable argument.
I've seen popularity referenced multiple times, and I very much dislike even considering if x amount of people use x technology - MUI is (in my books) focused on performance, DX, and other things, just not popularity.
MUI didn't always have 60k stars, it got them because it chose the best tech (or close to), not because it chose popular tech.
If choosing based on popular vote is in regards to being a more widely approachable project, that's business concerns, not possible performance enhancements. A project lives with or without users. It dies with bad choices. I think there's so many sayings around this and reading "it isn't popular enough, therefore it is a bad choice" rings a lot of loud bells.
People use a right product because it is good, not because it uses popular technology; MUI was niche once but became famous even though it had CSS-in-JS, which didn't win the popular vote btw. It just has some amazing properties and made the right choices that weren't based in current community but the actual DX and performance.
That sidenote being noted, I am on the side of the popular vote myself; so if anything, I am also sabotaging myself. I don't have any personal gain to have from choosing a way less popular product, I have the opinion that popularity should not be considered _at all_ when talking about revolutions and changes. Please reconsider some of these options based on what they actually are, not what people think they are based on the current popularity of the option.
To actually finish off, I am grateful for every thought and any amount of time going into MUI. I have made some amazing (sadly private) solutions following all standards etc. the past couple years, which would have taken months or years to make singlehandedly! I can't describe my appreciation nearly enough for it to shine through on paper ๐โโ๏ธ ๐ ๐โโ๏ธ
I'm curious if Compiled even is an option and how it would work with adapters and such. I think the Compiled approach:
Compiled compiles your CSS in JS at build time by statically analyzing your code and then transforming it into Compiled Components. Everything we need to use the component is included along side it in the JavaScript bundle.
is a path to think about, given the whole compiling 'css at runtime' constraint.
I'm saying this as Emotion maintainer - Compiled is great. Or rather - it might be in the future, this is very exciting stuff but it's still quite early in the experimentation. I highly doubt that MUI can go with it at this point in time.
Correct me if I'm wrong but compiled implies having a config which means it would be obligatory to have a config file for MUI even without using any custom styles.
I would hate to be forced to create a config just to use MUI. On a side note: wouldn't that be hard to use in opinionated bootstrappers like Create React App?
@Andarist I agree entirely. I would suggest starting a collaboration or at least considering participating in the development of the library. I'm inquisitive about where it could lead in the future! :eyes: I think something like compiled - as you're saying - in the future is going to be great. It would be awesome to have more great minds get together to make something remarkable.
@shilangyu I am not sure what you are implying, since I might be missing something. So I'll just say that the frontpage of compiled has this to say about it:
Migrate to a zero config reality
The APIs we love are all here for the ride - CSS prop and class names component too! Our consumers don't even need to change how they consume our components, continuing the zero config story they don't need to configure their bundler, nor do they need to setup any specific things for server side rendering. It just works.
Just the beginning
With zero config out-of-the-box today, we're not forgetting what tomorrow could look like. With the possibility for optional CSS extraction, transforming the CSS to an Atomic form, and even being able to use the CSS data for analysis across our code base, we're thinking up an exciting tomorrow.
@MathiasKandelborg
I skimmed through https://compiledcssinjs.com/ . Isn't it still runtime css-in-js ?
It creates css classes at build time but it applies that style(creates style tag with build time generated css classes) with <CC>...</CC>
tag at runtime.
If it is as fast as just using pure css then it really is the future(as it uses css variables). Thanks for sharing
I wonder how faster it is compared to Emotion.
What about an actual zero-runtime library? I haven't seen anyone mention linaria.
What we didn't include in the requirements is that any solution has to be zero-config from the perspective of Material-UI consumers. If I understood zero-runtime solutions then they generate some CSS at compile time. Don't I have to setup my bundler to include it properly?
So while zero-runtime is probably the fastest solution it also requires extra attention. Having a zero-config solution that can be configured to run with zero-runtime would be ideal I guess.
So while zero-runtime is probably the fastest solution it also requires extra attention. Having a zero-config solution that can be configured to run with zero-runtime would be ideal I guess.
Cant really say about current state of Compiled but i was talking about it several times with the maintainer and this roughly is the plan - the idea is to keep support for Emotion & Styled Components APIs, so optimizing code written those should just be a matter of changing the imports and including a transform plugin or a webpack loader. It, for sure, wont handle all code that can be possibly written (JS is wild), but it shohld be able to handle sensibly written code. If it wont be able to compile something the. It will simply throw - forcing one to ditch using it or rewriting a particular part of the code to aid static analysis.
So to sum up - if u go with 0config Emotion (or Styled Components) then it should be possible to adapt Compiled as an optional optimization in the future (if the project will manage to deliver what it promises)
@ko-toss I think it compiles into the styled component at build time. At runtime, the styles from the component are then moved to their rightful place.
As they say on the webpage:
Everything we need to use the component is included along side it in the JavaScript bundle.
We take your initial code in all its glory:
import { styled } from '@compiled/css-in-js';
export const ColoredText = styled.span`
color: #ff5630;
`;
And then transform it into a Compiled Component:
...
...
Which then at runtime will move the styles to the head of the document.
This kind of transformation allows us to deliver your component to any consumer, without needing them to configure/setup their tooling. Just import and go. This is powerful, and more importantly exactly the same as current CSS in JS libraries work - with one catch.
CSS can't be generated at runtime.
Having a zero-config solution that can be configured to run with zero-runtime would be ideal I guess.
I think you hit the nail on the head. It would feel utopian to suddenly just do that dreaming fondly.
There are some ideas to explore and maybe some collaboration to be had. Some of the code and concepts are a bit foreign to me, so I'm not in the position to go in many details. Here are some of the things I'm excited about:
In regards to IE11 support, how are you looking at stats? I'm sure it's a perfectly viable thing to do. Edge is now based on chromium, and most businesses should be making the switch when MS finally stops support for IE when each OS IE11 was installed on reaches the end of their support cycle. It is indeed a long cycle, but I think maintainers also have a part in pushing changes, and keeping support for something that is essentially deprecated seems to enable people to wait until the 'shift' actually happens.
It would be nice to have the option not to support IE11. It isn't industry standard anymore, and will be deprecated. It is a matter of time, and _default_ support from amazing things like MUI probably holds back the shift.
It would be nice to have the option not to support IE11.
See https://github.com/mui-org/material-ui/issues/14420 for that.
We don't plan to drop support for IE completely. The default version likely won't target IE 11 in v5 but we can't choose a solution that won't work at all in IE 11. Or rather it should be a solution that we can swap out at build time and produces the same output.
This makes me happy.
is there a code mod for converting existing jss to styled/emotion I wonder?
Hello everyone. I'm taking the opportunity to shim into this discussion.
In the current version, Material UI makes heavy use of withStyles
HOC without any dynamic styles (style being a function that depend on props), which internally uses makeStyles
. The performance of makeStyles
(without dynamic props) is quite remarkable and Material UI could even be faster if it was using it directly, instead of withStyles
, which creates an unnecessary wrapper.
I have created a benchmark forked of this benchmark, and I deployed it to Vercel, so that all code is compiled with production flags on. The benchmark renders cards using different CSS in JSS libraries. Here are the links:
For 100 cards:
makeStyles
: https://csb-5z6e2-lh4u8acll.vercel.app/?cases=mui-make-styles&cards=100emotion
: https://csb-5z6e2-lh4u8acll.vercel.app/?cases=emotion-styled&cards=100styled-components
: https://csb-5z6e2-lh4u8acll.vercel.app/?cases=styled-components&cards=100For 500 cards:
makeStyles
: https://csb-5z6e2-lh4u8acll.vercel.app/?cases=mui-make-styles&cards=500emotion
: https://csb-5z6e2-lh4u8acll.vercel.app/?cases=emotion-styled&cards=500styled-components
: https://csb-5z6e2-lh4u8acll.vercel.app/?cases=styled-components&cards=500For 2500 cards:
makeStyles
: https://csb-5z6e2-fqtfkzcrk.vercel.app/?cases=mui-make-styles&cards=2500emotion
: https://csb-5z6e2-fqtfkzcrk.vercel.app/?cases=emotion-styled&cards=2500styled-components
: https://csb-5z6e2-fqtfkzcrk.vercel.app/?cases=styled-components&cards=2500Overall, emotion
and styled-components
are very similar in performance. However, makeStyles
seems to be 2-4x faster overall on mount and rerender 6-8x
faster for updates.
The difference is significant enough, especially when we are rendering on low-power devices, such as our phones.. and there are a lot of crappy phones out there.
All of this to say that I'm worried about material migrating and using emotion
by default, which will decrease the rendering performance of Material UI and sites using it by a 3-5x factor. (this is not actually true, it depends on the component; the more complex it is, the less difference there will be).
Some questions and food for thought:
makeStyles
makeStyles
has to to with dynamic styles which seems to be fixable by implementing a deterministic cache id. Currently, every component instance gets its own id for dynamic props, even if props and output styles are the same, causing runtime overhead, many style tags in the head, and decreased SSR performance. Seems fixable by using a hashing strategy for dynamic styles, just like many other CSS in JS libs are doing it. Related: https://github.com/mui-org/material-ui/pull/16858emotion
and styled-components
to get closer, or even be better than makeStyles
?I can live with a small performance loss.
Not a 300% performance loss, not at any cost. ๐
@satazor thanks for exploring this. We did a heavy perf testing before starting this effort, see PR https://github.com/mui-org/material-ui/pull/22173 for more details (we did it on the ListItem component) and the perf difference was at most 10% for rendering x1000 instances, in production mode.
https://deploy-preview-22173--material-ui.netlify.app/performance/list-raw/
https://deploy-preview-22173--material-ui.netlify.app/performance/list-mui/
https://deploy-preview-22173--material-ui.netlify.app/performance/list-styled/
https://deploy-preview-22173--material-ui.netlify.app/performance/list-styled-wrapper/
Based on this, we decided to ignore this difference, because of the benefits we would get (dynamic props out of the box, styled API that was already used by a big percent of the developers already etc - the whole summary can be find in the PR description :))
Not sure what is happening on your benchmarks, but 3-5x seems too much to me, it makes me wonder why would anybody use emotion
/styled-compoenents
if this was the case.. We can try to see where is the difference between the two benchmarks, in case we are missing something. Also, doing benchmarks on a real MUI component would be much better in my opinion, so we would get more realistic numbers, so let me know if you want to explore more on this side. The PR I linked is a good starting point.
Thanks for the reply @mnajdova. You are right that testing on a Mui component would be more realistic. What's probably happening is that the Mui code for the List components is the predominant slowness factor, and the difference between them (~30ms) is the actual rendering time difference associated with styles. I will take the code of that PR and add it to the benchmark, to see the results.
Will this matter in the end? Probably not, but it depends on the app. The performance difference between current Mui components and styled ones will increase as the rendering code itself is simpler. As an example, I'm expecting to see increased differences on the Icon or Typography components, but decreased differences for Cards. So, it really depends on the app and the amount of components of each type the app is using.
which will decrease the rendering performance of Material UI and sites using it by a 3-5x factor.
You've created a benchmark that has this factor. It does not follow that every single component will show this decrease. Please try to avoid jumping to conclusions since this misleading information spreads very easily from such a visible issue.
Using the devtools extension I saw 140ms for mount with emotion vs 120ms for mount with makeStyles.
You've created a benchmark that has this factor. It does not follow that every single component will show this decrease. Please try to avoid jumping to conclusions since this misleading information spreads very easily from such a visible issue.
You are right, see my previous comment.
You've created a benchmark that has this factor. It does not follow that every single component will show this decrease. Please try to avoid jumping to conclusions since this misleading information spreads very easily from such a visible issue.
Using the devtools extension I saw 140ms for mount with emotion vs 120ms for mount with makeStyles.
I've updated the benchmark to use actualDuration
instead of baseDuration
, so we should now see values more inline with what is shown in the devtools profiler. The baseDuration
measures the time without memoizations, while actualDuration
is the opposite. Please note that this change only affects the rerender performance, and now I'm seeing makeStyles
6-8x faster for rerenders, which means it has better caching/memoization? However, I'm not getting the values you are seeing. Can you try with the updated links?
@satazor I don't think that your test cases are equivalent. We should be good.
A couple of changes you can try to understand that and that will reduce the difference of performance:
<MenuItem>
is almost x10 slower than a <li>
).Indeed, @oliviertassinari. It seems the performance going forward with emotion/styled-components is more in the 1.5x-2x factor max even for simple components, such as Typography
, which I have implemented here: https://codesandbox.io/s/css-in-js-comparison-forked-lr3sr?file=/src/components/EmotionTypography.js.
Check the production build & benchmark at: https://csb-lr3sr-7lp24bj5l.vercel.app/
makeStyles
is 1.5-2x faster on mount and 3-4x faster on rerenders. This is potentially something to keep an eye on, but I guess the deviation will be much smaller for more complex components.
So, in conclusion, I'm no longer that worried about the performance and I'm looking forward to see how this effort will look like.
@mnajdova Here's the production build for the List test: https://csb-lr3sr-3zi42510w.vercel.app/?components=1000, copied of the PR you mentioned. Codesandbox link: https://codesandbox.io/s/css-in-js-comparison-forked-6s4nl
makeStyles
seems 1.7x faster on mount, and 2.2x faster on rerender. Iโm not getting the 10% difference you are seeing. Am I doing something wrong?
@satazor Interesting, thanks for putting it together. I have used this benchmark with #22435 to compare the performance of
import Slider from '@material-ui/core/Slider';
vs (emotion).
import SliderStyled from '@material-ui/lab/SliderStyled';
vs (styled-components).
import SliderStyled from '@material-ui/lab/SliderStyled';
At this point, it's hard to tell why it's slower. The bottleneck might not be on the styles. And mind that I have run it in dev mode โ ๏ธ!
I have added two new pages to have a look at the performance of the WIP emotion version of the Slider:
Once built for production, the stats seem to be similar to https://github.com/mui-org/material-ui/issues/22342#issuecomment-697540546, it's about x1.6 slower (but CSS is fully dynamic). Note that you can play with it the WIP emotion version with:
Also, note that we know that we could make the current JSS version x1.1 faster by using makeStyles instead of withStyles: #15023.
@oliviertassinari in prod mode things get a bit faster, but I guess the differences stay there. You may click on deploy > vercel on code sandbox to quickly deploy with production build flags.
Looking at how makeStyles
is implemented, I see how it is faster when you just use static styles:
attach
gets called.stylesCreator.create
gets called, which in turn calls fn
specified in makeStyles(fn)
.stylesCreator.create
is skipped because the ref count is > 0.For rerenders:
attach
gets called.stylesCreator.create
is skipped because ref count is > 0, so no work is done at all.Please note that if dynamic styles are into play, the sheets would have been updated here, on every mount and rerender.
On the contrary, styled-components
and emotion
seem to run our styling functions on every component instance, which results in more CPU cycles and memory backpressure. I thought they could somehow do a multi memoize cache based on props combination, but this would assume that the styling functions are pure, which might not be the case, consider:
const someContext = useContext(FooContext);
return <div css={ { paddingTop: someContext.padding(1) } }>;
If my assumptions are right, it will be very hard to reach the performance level of makeStyles
for static styles generation, as the way it works and how the API is designed allows for optimizations that styled
or css
API can't.
I see a couple of possible directions we could explore:
If somehow emotion
exposed a useCss
hook like it was requested in https://github.com/emotion-js/emotion/issues/1321 and https://github.com/emotion-js/emotion/issues/1853, we could retain makeStyles
API and consequently, the benefits of "static CSS". However, we would keep using static CSS everywhere, to boost performance, which is not so "clean" but that's what we are already doing in v4.
Actually, with the ClassNames
API, I think we could do a port of withStyles
right now that would retain the benefits of the static CSS perf and the good performance of dynamic CSS that emotion has. If const css = useCss()
existed, then it would be straightforward to create a useStyles
API port as well.
The main advantages of keeping withStyles
+ makeStyles
API which uses emotion under the hood are:
withStyles
and makeStyles
outside of Material UI, wouldn't need to migrate at all. They would get the benefit of improved performance for dynamic CSS, for free.classes
+ CSS API. With styled
we would need to create the global className
s by hand, or with a util.useCss
is our adapter function for CSS in JS solutions, instead of styled
.styled
.We have explored the performance issue further in https://twitter.com/olivtassinari/status/1309247827839680512. I think that we can move forward as is. For teams that care deeply about performance, they can opt-in into the unstyled components, they provide better performance. For the others, like most of the industry, emotion and styled-components are good enough.
https://codesandbox.io/s/slider-comparison-forked-jziv6?file=/src/App.jsโฆ
Sorry that I bother you here so late in the discussion but I'm a bit surprised you are not looking closely at styled-jsx
Their list exactly met your requirements:
I would pay attention to the fact that it is almost a shadow CSS standard API. So by removing jsx
attribute you are good to transition to web components in the future which are working already in the normal browsers BTW.
Yes I know it might be not the most popular one.
But I just want to point out that Flash was very popular some years ago.
But it dried out at the end not being web standard compliant, and we have SVGs now.
Just for the record SVG standard was present long when Flash was ruling the industry.
I just look at historical events as good lessons and would try to spot the pattern that popularity is the last indicator of being bulletproof maintainable and future proof.
@mifrej I personally had a bad experience with it: https://github.com/vercel/styled-jsx/issues/142.
We have explored the performance issue further in https://twitter.com/olivtassinari/status/1309247827839680512. I think that we can move forward as is. For teams that care deeply about performance, they can opt-in into the unstyled components, they provide better performance. For the others, like most of the industry, emotion and styled-components are good enough.
- native: 7.71ms
- v5 unstyled: 20.89ms
- v4: 29.93ms
- v5: 37.37ms
- antd: 53.48ms
- chakra: 64.67ms
https://codesandbox.io/s/slider-comparison-forked-jziv6?file=/src/App.jsโฆ
Did you try the babel plugins for emotion / styled-components? Did it make a difference to the timings?
What would a change from JSS mean for the classes
prop available on existing MUI components? How would a v5 migration look for existing users that leverage this prop extensively?
We envision people to use the following syntax instead: https://next.material-ui.com/components/slider-styled/#unstyled-slider the classes are basically replaced by the class selectors available for each slot in the component. You can take a look also on the customization example: https://next.material-ui.com/components/slider-styled/#customized-sliders
As an advantage you can just use the props and apply dynamic styles based on them.
We envision people to use the following syntax instead: https://next.material-ui.com/components/slider-styled/#unstyled-slider the classes are basically replaced by the class selectors available for each slot in the component. You can take a look also on the customization example: https://next.material-ui.com/components/slider-styled/#customized-sliders
As an advantage you can just use the props and apply dynamic styles based on them.
I love this API! Very much a welcome change, and it seems to play really nicely with the style engines.
Before v5
, if I recall correctly, the JSS compiler would mangle those class names and you couldn't reliably target them? But now it seems they'll be exposed for targeting purposes? ๐ Also, there was the issue with CSS precedence. And those concerns are resolved with this new approach? Thank you for working on this refactor!
@ConAntonakos exactly these classes can be targeted for both the unstyled and styled versions of the components. The order of which styled is invoked ensures that the new styles will win, of course if the specificity is the same :)
Before v5, if I recall correctly, the JSS compiler would mangle those class names and you couldn't reliably target them?
You could already target them in v4.
the classes are basically replaced by the class selectors available for each slot in the component.
Are they "basically" replaced or actually replaced? I thought we decided to keep some of the old API to reduce the number of breaking changes.
I thought we decided to keep some of the old API to reduce the number of breaking changes.
We decided to keep the same API for the theme.components.overrides
- overrides defined in the theme work in the same manner.
For the instance overrides, we have the styled
approach now with the class selectors, that is why the classes
prop is not supported anymore. Developers can do that same in more flexible manner now.
Developers can do that same in more flexible manner now.
That sounds like it's such a minor issue because there's an alternative but the migration cost for that is huge. How does the migration plan look like?
Developers can still use the theme overrides, if they just move the instance overrides to a nested ThemeProvider
they wouldn't need to change the styles defined at all, as the structure between those two is the same (it's not perfect, but if they want incremental upgrade it is a way to go)
On the other hand, we can still support the classes prop easily, but in that case we cannot guarantee if the combination of classes + styled is used on the same component which one should win. Should we backport the support of classes at least on the styled version of the components?
I may have missed this along the way through this thread - another related question to my classes
question. What sort of "correctness" guarantees might there be?
For example i've edited the slider example:
const StyledSlider = styled(SliderUnstyled)`
& .MuiSlider-raill {
display: block;
position: absolute;
width: 100%;
height: 2px;
border-radius: 1px;
background-color: currentColor;
opacity: 0.38;
}
)
You'll notice i accidentally misspelled MuiSlider-rail
. Previously with classes
there would be something like classes.rail
, and if i misspelled the property, i would get a runtime warning that classes.raill
doesn't exist in the stylesheet. I believe the Theme had the same behavior?
The advantages of the classes
API I can think of:
.css-e7ylz8 .MuiTreeItem-group
. You have no guarantees that the component doesn't apply the style on a child component (not the effect you were expecting, a surprise!). Probably OK-ish for our components as we will be careful.$styleRule
syntax warns if the style rule is undefined.componentsProps
prop. We merge the class names. There is an alternative world where we would:
a. Allow to solve 1. and 3. with styled component selectors.
b. Expose the classes
API for backward compatibility.
c. In order to get a. and b. working, we would need to flatten how the styles of the component are written internally. x styled component instead of 1 styled root. But โ ๏ธ with the perf implication.
Do we really need to do that?
I have looked at the history of jQuery UI's classes
prop. I could find two issues: https://bugs.jqueryui.com/ticket/7053, https://bugs.jqueryui.com/ticket/8928 and the initial commit: https://github.com/jquery/jquery-ui/commit/c192d4086d9bbaf09d5f870857af30c60a427e22.
We envision people to use the following syntax instead: https://next.material-ui.com/components/slider-styled/#unstyled-slider the classes are basically replaced by the class selectors available for each slot in the component. You can take a look also on the customization example: https://next.material-ui.com/components/slider-styled/#customized-sliders
As an advantage you can just use the props and apply dynamic styles based on them.
Wow, this is the best thing ever.
Unstyled or Headless components is going to be the best thing for customization (one of the critics about mui, I think).
This is not a little thing to fix imo, but a hude plus for MUI.
PS : I remember some hard time customizing some components in the past
PS2 : Did you take a look at https://github.com/modulz/stitches ?
You'll notice i accidentally misspelled MuiSlider-rail. Previously with classes there would be something like classes.rail, and if i misspelled the property, i would get a runtime warning that classes.raill doesn't exist in the stylesheet. I believe the Theme had the same behavior?
@ianschmitz in addition to the option @oliviertassinari suggested for using the styled components selectors, we have another option, which is to expose constants for the classes that we expose. Maybe something like:
import { sliderClasses } from '@material-ui/core/Slider';
const StyledSlider = styled(SliderUnstyled)`
& .${sliderClasses.rail} {
display: block;
position: absolute;
width: 100%;
height: 2px;
border-radius: 1px;
background-color: currentColor;
opacity: 0.38;
}
)
It's not the same as the classes.rail
runtime warning, but should help against misspelling the classes.
@mnajdova We could also consider an eslint plugin.
Regarding the support on the classes
prop - in order for us to be able to reliably do this, we will have to create components for each part (slot) of the core component. For example, for the Slider
, we would need to create components for the rail, track, mark, mark label, thumb and the value label. This will allow us to specify the styles directly on those components, instead of using classes for increasing the specificity. These changes can be find on this PR - https://github.com/mui-org/material-ui/pull/22893
With these changes, we've created a codesandbox, that can compare the perf of this new updated Slider component compared to the v4, native styled, unstyled, as well as two other competitive libraries - https://codesandbox.io/s/slider-comparison-with-multiple-components-2tytc?file=/package.json
If we compare these perf with the perf of having only one component and using the classes selectors for the parts of it - https://codesandbox.io/s/slider-comparison-forked-jziv6?file=/src/App.js we will notice that adding components per slot has an 20% perf degradation ๐ข
Production versions:
To be honest I don't know at this point whether it's better to add this backward compatibility or not.
Are these any real use-cases for the the support of the classes
or is it just for easing up the upgrade?
Are we ok with having 20% perf degradation only for easing the migration path?
Is there some alternative that we cannot see, that would help us to do both of these without paying the perf cost?
@ianschmitz @eps1lon @oliviertassinari and others :) are there any thoughts on this?
As long as we can define and use themes & styles with TypeScript, I wouldn't mind spending time migrating compared to losing 20% perf
I'm generally curious, and forgive me if I don't understand the underlying design, but classes
was an API for JSS? If the API design is switching from JSS to styled components, does it make sense to keep supporting classes
?
Are these any real use-cases for the the support of the
classes
or is it just for easing up the upgrade?
Are we ok with having 20% perf degradation only for easing the migration path?
Is there some alternative that we cannot see, that would help us to do both of these without paying the perf cost?
Apologies if i've missed anything with the proposed API, but IMO the use case I most often see within our org is the abstraction of the underlying styling system used by MUI. Yes i guess classes
is sort of an "API for JSS" as @ConAntonakos mentioned, but to the consumer it didn't matter. As a consumer I could use the CSS tech of preference (are there any limitations today with classes
?). We have a number of products using a variety of:
depending on the needs and preferences of those teams.
Exporting the class names helps if you're using some flavor of CSS-in-JS, but what are the thoughts for those that aren't?
RE. 20% perf, i agree that is likely not an acceptable trade-off. At the end of the day you guys should do what's best for the majority of the community. Just offering my thoughts ๐
One wish I never got was that material-ui would be react-native compatible. Many projects are cross platform these days and having a unified styling solution offers a lot of advantages for cross platform components. We ended up rolling our own using material-ui on the web side and react-native-paper on the native side and standardizing on the material-ui API. I'd be interested to understand if this new styling solution will make the use of (some/all) Material UI components on react-native a possibility? Any window references in components would obviously be a blocker, but the styling itself supports native as well doesn't it?
@mschipperheyn react-native is a no-goal so far. It's +5% of usage potential (1 month of growth) and +50% more effort (a guess). The opportunity cost is really high with no obvious direction on how to monetize it (outside Ionic's model). Also, mind that flutter seems to have captured a large chunk of the audience that react-native targets.
Now that v5 is in alpha release, is there a resolution to this issue? In particular, is the styling solution still based on JSS? We've seen substantial performance issues related to JSS, so have been eagerly anticipating a new solution.
@zzzev This isn't an issue per se. It's an RFC (Request for Comments) thread.
I'm inquisitive about which substantial performance issues you're talking about and how going from JSS would improve that. Because the way I see it is that if you have performance problems, it's probably not the styles but how they're implemented, i.e., the same result could be achieved by writing the styles in another way, using less processing power.
At the very least do I fail to relate to how going from JSS to Emotion (which is shown in this thread to _most likely_ have some performance degradation) would improve anything.
My understanding is that emotion will cause a slight hit to static styles performance, and much better dynamic styles perf -- but maybe that's not quite right? There are a lot of different numbers in this thread and it's hard to reconcile into one picture of performance (and obviously it depends a lot on an individual's situation).
When you say we should write the styles in a different way, do you mean avoiding dynamic styles? Or are there other best practices we should be considering?
@zzzev Correct on the first part, not quite on the second (unless you count going from unsupported to supported as an infinite performance gain ๐).
Emotion enables support for dynamic styles, at the cost of moderately slower performance for static.
I'm confused; aren't there dynamic styles in the current/v4 makeStyles? e.g. this pattern
I'm confused; aren't there dynamic styles in the current/v4 makeStyles? e.g. this pattern
There are but there's a big known perf issue. My team stays far away ATM
I just hate component-styled
jss is good but there are a few problems in debugging, performance and still some bug still not resolved such as nested like&:after
it's my packages build-up for react-native and react-native-web
https://www.npmjs.com/package/@material-native-ui/theme-provider
I`d like something like this (it's build-up on top of RN and RNW)
So is there a conclusion on the recommended style solution to use with Material UI v5? It seems that there is an intention of moving away from JSS which @material-ui/styles
is currently built upon. Or @material-ui/styles
will be refactored to build upon other styling solutions like styled-components
instead?
So is there a conclusion on the recommended style solution to use with Material UI v5? It seems that there is an intention of moving away from JSS which @material-ui/styles is currently built upon. Or @material-ui/styles will be refactored to build upon other styling solutions like styled-components instead?
@matthewkwong2 we wouldnโt adopt the @material-ui/styles
package to the new styled engine, it will keep supporting jss. In v5 it will be isolated to the rest of the codebase and we plan to remove it in v6, meant to help transition to the new styling engine.
For v5, we will have new beat practices regarding the styling solution, like the sx
prop and the styled
utility, we still work on the documentation around this.
Also the theme overrides and variants are still going to be supported in v5.
For v5, we will have new beat practices regarding the styling solution, like the sx prop and the styled utility, we still work on the documentation around this.
Also the theme overrides and variants are still going to be supported in v5.
So if I understand correctly, for the styling of individual components, it is encouraged to use sx
or styled
instead of makeStyles
.
But what about the theme (i.e. createMuiTheme
)? I believe that part is also built upon JSS right? What would be the recommended way to create a theme (i.e. with the main purpose of defining global styles) now?
We still keep the same structure for creating the theme, we just expect that the values for the components overrides & variants follow the syntax for emotion/styled-components. There are no changes in how the theme is created, the API is exactly the same, the same theme context is reused for the new styled engine too. Does this makes sense @matthewkwong2 ?
@mschipperheyn react-native is a no-goal so far. It's +5% of usage potential (1 month of growth) and +50% more effort (a guess). The opportunity cost is really high. Also, mind that flutter seems to have captured a large chunk of the audience that react-native targets.
I don't want to take us on too big of a tangent, but I would like to push back on some of these rationales.
the switch to emotion has likely eliminated 2/3 of the difficulty in making MUI work in RN
We look forward to seeing your POC ๐
We look forward to seeing your POC ๐
I'd love to play around with it if I have a chance. But people generally don't bother making POCs for things that maintainers show a disinterest for. No point building something when the current atmosphere is that it'll probably just end up abandoned. Hence why I want to push away from dismissing the value of RN or the value of RN as a possibility for the future.
Two questions:
classes
prop most components have still be supported (it would give full flexibility in what styling solution users can go with)?the fast-refresh
is enabled by default in create-react-app v4. should we add fast-refresh support as a new requirement?
Trying this out with gatsby. When I do import { Link } from '@material-ui/core'
I got:
Can't resolve '@emotion/core' in 'node_modules/@material-ui/styled-engine'
File: node_modules/@material-ui/styled-engine/index.js
Can't resolve '@emotion/styled' in '/node_modules/@material-ui/styled-engine'
File: node_modules/@material-ui/styled-engine/index.js
When changed to import Link from '@material-ui/core/Link'
problem gone.
If I install @emotion/styled @emotion/core
I got:
Can't resolve '@emotion/react' in '/node_modules/@emotion/styled/dist'
Then I install @emotion/react
.
A runtime error comes in.
Error: The `@emotion/core` package has been renamed to `@emotion/react`. Please import it like this `import { jsx } from '@emotion/react'`.
./node_modules/@emotion/core/dist/emotion-core.cjs.dev.js
node_modules/@emotion/core/dist/emotion-core.cjs.dev.js:3
Involved package versions:
"@emotion/core": "^11.0.0",
"@emotion/react": "^11.0.0",
"@emotion/styled": "^11.0.0",
"@material-ui/core": "^5.0.0-alpha.15",
"@material-ui/lab": "^5.0.0-alpha.15",
Install v10 versions of Emotion packages
Oh 11 is the "latest" version now so I think mui need to upgrade or document that
Oh 11 is the "latest" version now so I think mui need to upgrade or document that
We have it documented via version ranges in peerDependencies
. We didn't mention it explicitly in the install instructions since we plan to update it to v11 soon.
Friendly reminder that this is an alpha and emotion 11 just a few days old. As an early adopter you should expect some rough edges.
Hello everyone, I'm new here, and I was looking at material-ui css solutions and came at this issue.
Just giving my 2 cents on this, I'd like to suggest Linaria https://github.com/callstack/linaria.
It's a zero runtime library, with css extraction and CSS variables as React props.
Hope this helps on this RFC ๐ .
Most helpful comment
Speaking as Emotion's maintainer - this sounds great ๐
We should also be able to release a new major soon-ish which won't be any revolution, just some cleanups, overall improvements, hooks under the hood and TS types improvements (better inference and performance).
Oh, and rewritten parser! that eliminates some edge bugs in Emotion and Styled-Components (as currently, they are both using the same parser). It is both smaller and faster.