Investigating Significant Performance Discrepancy Between @emotion/react and @emotion/css
Hi Emotion team 👋
First off, thank you for your amazing work on Emotion. We’re long-time users at Elastic and really appreciate the flexibility and power the library offers.
We’re currently working on a large-scale migration from SCSS and styled-components to Emotion, and during performance investigations, we’ve uncovered significant and repeatable performance differences between @emotion/react and @emotion/css. The tests were run in Kibana using reproducible test cases, and later simplified into a CodeSandbox.
Summary of Findings
-
@emotion/react renders significantly slower than @emotion/css.
-
Memoizing styles improves performance with @emotion/css but has negligible (or sometimes negative) impact when using @emotion/react.
-
Some optimizations (like moving conditionals outside of css) only benefit @emotion/css.
We suspect the root issue might be the lack of Emotion Babel plugin optimizations (e.g., caching), since Kibana currently includes both styled-components and Emotion, which may prevent us from using Emotion’s Babel plugin fully. Plus we cannot use babel plugin in codesandbox.
Questions
-
Is this performance difference expected between @emotion/react and @emotion/css?
-
Does the lack of the Babel plugin severely penalize @emotion/react performance? (even if using object syntax like we do)
-
Are there known scenarios where @emotion/css should be preferred for performance-critical paths?
-
Can @emotion/react be optimized in any way without dropping support for styled-components (which is still in our codebase)?
-
Would you be open to profiling some of these examples or confirming if this is something Emotion itself could improve?
Repro Info The idea of the app I wrote is simple – we show multiple scenarios on the page and render X components Y times. There's a radio list at the top of the page at the right, to choose between scenarios that render the same components using @emotion/css and @emotion/react.
The test case renders 2,000 components 3x across several strategies (inline, memoized, externalized, etc.), but the trends are visible with way less.
Here are some performance stats (at the bottom of the page) for @emotion/css:
And for @emotion/react:
Happy to provide more benchmarks, screenshots, or collaborate on further tests if it helps. This is quite impactful for us as we define best practices for Emotion usage at scale, and any help or clarity would be incredibly appreciated.
Thanks again!
Other examples:
Thank you for a detailed issue. It is on my radar and I hope to investigate and respond in the coming week.
Thanks @Andarist! While I have your attention, I'd have one more question when you find a moment — slightly off-topic, but I'm curious what you think about the performance concerns raised in this article: https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b
I’ve done some pretty extensive testing on components with heavy use of css props (and compared to SCSS), and I haven’t been able to reproduce anything close to the kind of slowdown the author reports. In my tests, Emotion doesn't seem to cause significant runtime overhead — in real-life scenarios it’s more like a 1%-5% or less difference (so not really significant), not the 50%+ reported there.
I’m just wondering how to explain such a big difference. Do you think it's outdated benchmarks, maybe a very specific setup, or something else? Curious to hear your take!
As to the article above... I'm not exactly sure - I have not been able to reproduce such overhead in the benchmarks I've done in the past. The more crazy you go with dynamic patterns the runtime cost naturally increases but I, honestly, always have seen the CSS-in-JS cost to be negligible.
As to the reported problems, I think the main issue here is the bigger React element tree that @emotion/react creates to get some boundaries and guarantees in place. It's not exactly something we can change right now without introducing breaking changes. I'm working on Emotion 12 (no ETA) and it's definitely something I'll try to address there (I already had a plan to address at least some of this). As to no ETA for this - there is some work that has to be done in React itself that is blocking further work on this in Emotion. I'm in contact with the React team, and we'll be discussing our options soon.
I'd happily discuss further over a call what your next steps could be and how could I assist you, if that's something you'd be up for.
Thanks a lot for the detailed reply, @Andarist — really appreciate you taking the time to dig into this and share some context. I’d definitely be open to a call – I’ll follow up via DM to coordinate.