21

I've just started using Material UI, and I know that it uses CSS in JS way of styling components.
I saw 2 methods in the documentation of how to create styles:

Using the sx prop:

<Box sx={{ backgroundColor: 'green' }}/>

Using the makeStyles method:

makeStyles({
  root: {
    backgroundColor: 'green'
  }
})

I know that CSS in JS is much less performant than native CSS.
But between these 2 methods I just wrote, which one is more performant (if any)?

By the way, I'm using Material UI version 5, which claims to have better performance overall with emotion instead of JSS

nil
  • 419
  • 1
  • 5
  • 12

2 Answers2

27

JSS is slightly faster than Emotion for static styles (i.e. styles that aren't dynamic based on props). JSS is much slower than Emotion for dynamic styles -- Emotion has similar performance for both static and dynamic styles.

You can find information about the performance difference for static styles between JSS and Emotion in the following issues:

JSS was about 10% faster than Emotion for static styles. For dynamic styles, JSS was 6 times slower than Emotion in one test the Material-UI team performed, and this is why JSS was eliminated from the list of possible styling engines for v5.

The documentation at https://next.material-ui.com/system/basics/#the-sx-prop contains the following performance information:

Benchmark case Code snippet Time normalized
a. Render 1,000 primitives <div className="…"> 100ms
b. Render 1,000 components <Div> 120ms
c. Render 1,000 styled components <StyledDiv> 160ms
d. Render 1,000 Box <Box sx={…}> 370ms

I would expect the performance of using Emotion directly (using either the styled approach or the css prop) to be similar to Benchmark case c. I would expect makeStyles for static styles to be slightly faster than that (in the 140ms to 150ms range), but not by much. You can see that the sx prop is notably slower, but keep in mind that the extra 200ms of overhead is for 1,000 elements so the additional overhead is still only one-fifth of a millisecond per component rendered. The amount of overhead added by the sx prop is dependent on how many CSS properties you pass to it. For a small number (< 5) of properties, the difference between styled and sx is not as significant as shown in the table above.

I don't recall seeing any claims by Material-UI that v5 is faster than v4 overall. v5 does add many new features that would have been hideously slow (due to leveraging dynamic styles) if implemented using JSS, so they were able to add those features while keeping the styling performance comparable to v4.

The biggest downside of using makeStyles with Material-UI v5 is that you would then be causing your users to download both JSS and Emotion as part of your bundle. If you have an existing application built with v4 that already uses makeStyles a lot (that you are now moving to v5), one migration option is tss-react which retains a similar syntax to makeStyles, but is backed by Emotion instead of JSS and has similar performance to the styled API. There is now a codemod for migrating JSS styles to tss-react.

Related answer: Why is the `sx` prop so much slower?

Ryan Cogswell
  • 75,046
  • 9
  • 218
  • 198
  • Can you even use ```makeStyles``` in material ui v5? Isn't it just ```sx``` prop only? – Two Horses Jul 14 '21 at 19:58
  • 1
    @TwoHorses Yes, in v5 you can use it via the `@material-ui/styles` package (https://next.material-ui.com/guides/migration-v4/#material-ui-core-styles), but it is considered deprecated. The `sx` prop is just an added convenience utility for styling the Material-UI components, but you can still provide CSS classes via any other styling solutions. – Ryan Cogswell Jul 14 '21 at 20:03
  • So if `sx` is only accepted by the `Box` component and I want to stay as close as possible to the preferred MUI-way of styling my components, removing all uses of `makeStyles` and `withStyles` in favor or Emotion or styled-components would be the way to go? Yikes, this will be a lot of work in my case. Thank you for taking the time to provide you insight here. – hotpink Jul 15 '21 at 06:52
  • 2
    @hotpink `sx` is supported by all MUI components—not just Box. – Ryan Cogswell Jul 15 '21 at 11:13
  • @RyanCogswell would you recommend replacing `makeStyles` with `styled`, and use `sx` sparingly because of the performance impact? There are some users that are intimidated by the `sx` perf number even though it's a good improvement for dynamic styles. I'm also interested in the perf of dynamic `styled` (passing a callback instead of style object) compared to the `sx` prop. – NearHuscarl Oct 23 '21 at 19:56
  • @NearHuscarl I don't think I would go so far as to say you should use `sx` "sparingly" -- mainly I would avoid using it for components for which a large number of elements are rendered on the page. I wouldn't have any concern about having 100 or less elements on the page using `sx`, but I would probably avoid it for list items, grid or table cells, menu items, and other higher volume elements. – Ryan Cogswell Oct 23 '21 at 20:14
  • @NearHuscarl As far as dynamic `styled` performance, it won't be notably different than when passing a style object as long as the function isn't doing anything expensive. – Ryan Cogswell Oct 23 '21 at 21:33
  • We migrated an app from v4 to v5 recently, moving all the styles to sx. Our build time was 10x slower after and the IDE was getting super slow. We found out somehow sx seems to be an issue for the typecheck er. After migrating all the styles from sx to className with emotion css we were back to normal. – platzhersh Dec 09 '21 at 06:38
  • Note that MUIs benchmarks are via their implementation of JSS and NOT pure JSS. this is done against the pure npm modules of the other packages without wrappers. I am not sure this is a good indication that dynamic JSS is slower than emotion – Jony-Y Jun 21 '22 at 20:35
  • What's the difference between b. Render 1,000 components
    and c. Render 1,000 styled components ?
    – nrion Dec 01 '22 at 10:07
2

I had the same problem, but then I decided to rebuild the makeStyles overall based on @emotion/css:

https://dev.to/atonchev/material-ui-5-the-easiest-way-to-migrate-from-makestyles-to-emotion-1i9l

Basically you will need to make one custom hook useClasses, which will rework your theme => ({... function or styles object into classes, that are used exact the same way like with makeStyles.

There is also IMO a huge benefit of using this approach compared to the way how it is proposed in the mui codemod:

https://github.com/mui-org/material-ui/blob/v5.0.0-beta.2/packages/material-ui-codemod/README.md#jss-to-styled

Because the emotion/css will cache same styles as one className, and you basically reuse classes, for example:

const styles1 ={
  someClass1: { color: 'black' }
}

const styles2 ={
  someClass2: { color: 'black' }
}

both styles1.someClass1 and styles2.someClass2 will have the same class name in production, e.g. css-1qs4g5r. I tryed it already. But in the mui proposed codemode-way you will have unique class names, which are not really reusable.

bukso
  • 1,108
  • 12
  • 23