CSS-in-JS is a commonly used concept when solving CSS problems and styling modern applications. When starting a new project, it can be tricky to decide on which CSS-in-JS library to use.
A problem we often run into is that most of the time, we’re building applications that will be used by a lot of people. An application can quickly scale to millions of users depending on its success, and choosing the wrong CSS-in-JS library for your project could end up costing a lot in the future.
The ecosystem of CSS-in-JS libraries is getting better every day, libraries are getting more mature and robust, new features and support are being added, and problems that were once really painful to solve are becoming easier.
Emotion is one of these CSS-in-JS libraries that is more mature and consistent, due to the work of the whole community involved. In this post, we will learn more about Emotion, and see the features and advantages that it can bring to our applications.
Emotion is a high performance, flexible, and performant CSS-in-JS library. Emotion helps us to style our application in a faster way, with a decent and consistent CSS composition.
Here are some of the features of Emotion.
Emotion is a really performant library because it uses a philosophy that comes from a library called glam. The idea is to have the best runtime performance without compromising the runtime cost.
The result is a super fast and small library that is really great for prototyping and design systems. With Emotion, objects can be used everywhere and it is easily composable with arrays.
Emotion is a framework-agnostic library, which means that it can be used in a different range of frameworks and libraries. You’re able to use it everywhere you want, with the same powerful API and features. This is not something exclusive to Emotion, we have some other CSS-in-JS libraries that are framework agnostic. However, the idea to reuse Emotion in different projects is fascinating because, for example, you could build a whole design system with support for web and mobile just using Emotion.
Emotion has a package called @emotion/native
that’s for React Native itself, so there’s no need for the developer to use Emotion on the web and use another CSS-in-JS library on mobile.
To start to style your React Native apps using Emotion, all you have to do is install the packages:
yarn add @emotion/core @emotion/native
Emotion requires no additional setup to get started. It has support for nested selectors, media queries, and auto vendor-prefixing. It’s really composable and great for prototyping, you can use just the CSS
function and the cx
to compose everything in your application.
To get started with Emotion, all you have to do is install the package:
yarn add emotion
Now you are able to create your first styled component using Emotion:
import { css, cx } from 'emotion' render( <div className={css` padding: 10px; background-color: red; font-size: 16px; border-radius: 6px; `} > Emotion CSS-in-JS </div> )
Emotion is still different in some ways from other famous libraries such as styled-components and Radium. Let’s understand some of the differences that separate Emotion from other CSS-in-JS libraries and what makes it so performant and flexible.
There are different Emotion packages, that were created for different use cases. When using Emotion in an application, you need to know the differences between these packages so you won’t be installing more than you need and increasing your bundle size.
The emotion
package is framework agnostic, so if you decide to use Emotion in other applications that are not using React, this is the right package for you:
yarn add emotion
The @emotion/core
package requires React, so this is the right package for you if you’re using Emotion in a React application:
yarn add @emotion/core
The first difference that we notice with Emotion compared to the other famous CSS-in-JS libraries is styling. The primary way to style components using Emotion is to use the CSS
prop.
The CSS
prop allows us to apply styles direct to our component or element without having to create a styled component. There are two ways to use the CSS
prop correctly.
First, if you’re working in a project that you are able to configure a custom babel config, you have to use the @emotion/babel-preset-css-prop
in your .babelrc
:
{ "presets": ["@emotion/babel-preset-css-prop"] }
In case you’re using some boilerplate or starter such as create-react-app, you might not be able to configure a custom babel config, you will need to use the second option, the JSX Pragma.
All you have to do is use the JSX Pragma on the top of your file that’s using the CSS prop, and import the jsx
from @emotion/core
, like this:
/** @jsx jsx */ import { jsx } from '@emotion/core'
JSX Pragma is basically a code that tells the babel plugin to use the jsx
function instead of React.createElement
.
Now, you can use the CSS
prop in any element of your file:
/** @jsx jsx */ import { jsx } from '@emotion/core' import React from "react"; const Header = () => { return ( <header> <h3 css={{ color: 'lightgreen'}}>Hello World!</h3> </header> ) };
A nice feature of the CSS
prop is that we can have access to the theme by default, by using a function that accepts the theme as the CSS
prop:
/** @jsx jsx */ import { jsx } from '@emotion/core' import React from "react"; const Header = () => { return ( <header> <h3 css={theme => ({ color: theme.color.primary}) }>Hello World!</h3> </header> ) };
A lot of people are using styled-components nowadays, another famous CSS-in-JS library. One of the features that they might miss is the styled.div
style API, that’s why Emotion has a package called @emotion/styled
.
To use this style API, all we have to do is install the @emotion/styled
package using the following command:
yarn add @emotion/styled
And now we can use the style API combined with template literals to create styles very easily:
import styled from '@emotion/styled'; const Button = styled.button` width: 100px; height: 40px; background-color: black; color: white; `;
Emotion also has support for theming, to work with it all we need to do is install the emotion-theming
package:
yarn add emotion-theming
The emotion-theming
package provides the ThemeProvider
, we should add this provider on the top level of our application and then we can have access to our theme in a styled component using the props.theme
:
import { ThemeProvider } from 'emotion-theming'; const theme = { colors: { primary: 'black', secondary: 'blue' }, breakpoints: { sm: 380, md: 720, } } const App = () => { return ( <ThemeProvider theme={theme}> ... </ThemeProvider> ) }
Working with media queries is simple using Emotion. For example, let’s imagine that we have an array of breakpoints:
const breakpoints = [576, 768, 992, 1200];
We can just create a helper function to return the breakpoint that we want, like this:
const mq = (n) => `@media (min-width: ${breakpoints[n]}px)`;
Now, inside our styled-components, we simply use our mq
helper function and pass the media query that we want:
const Text = styled.h3` font-size: 16px; color: black; font-family: Inter; ${mq(1)} { color: green; } ${mq(2)} { color: hotpink; } `;
Server-side rendering is a popular technique and works out of the box with Emotion if you’re using the @emotion/core
and the @emotion/styled
packages.
The default approach is to use the renderToString
from React which will insert a <style>
tag above your element:
import { renderToString } from 'react-dom/server' import App from './App' let html = renderToString(<App />)
The advanced approach is just in case you need to work with nth child
or similar selectors, since the default approach is not the best for it. It requires a few more lines of code, but it works fine.
In your server, put the following code:
import { CacheProvider } from '@emotion/core' import { renderToString } from 'react-dom/server' import createEmotionServer from 'create-emotion-server' import createCache from '@emotion/cache' const cache = createCache() const { extractCritical } = createEmotionServer(cache) let element = ( <CacheProvider value={cache}> <App /> </CacheProvider> ) let { html, css, ids } = extractCritical(renderToString(element)) res .status(200) .header('Content-Type', 'text/html') .send(`<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>My site</title> <style data-emotion-css="${ids.join(' ')}">${css}</style> </head> <body> <div id="root">${html}</div> <script src="./bundle.js"></script> </body> </html>`);
Now, on the client-side, all you have to do is the following:
const cache = createCache(); ReactDOM.hydrate( <CacheProvider value={cache}> <App /> </CacheProvider>, document.getElementById('root') );
Emotion is a really performant and consistent CSS-in-JS library, in comparison with other libraries like styled-components. There’s a lot of content and comparisons between those two libraries, saying that Emotion is 25x faster than styled-components, etc. Even with the release of styled-components v5 last year, Emotion still has a little advantage over styled-components because it has a smaller bundle size and faster runtime. Aside from performance and runtime, both libraries have almost the same functionalities and features.
So, should you use Emotion? There’s not an exact answer to this question, because it really depends on a lot of factors.
If it is your first time using a CSS-in-JS library you may want to start with styled-components. For a better understanding of CSS-in-JS in general, styled-components will work better for you and help to understand the principle concepts of CSS-in-JS and how it can work in real projects. The amount of content available by the community is huge and you can learn about CSS-in-JS really fast.
Have you used a CSS-in-JS library before and are looking for a smaller and faster library? I would go with Emotion. If you’re used to using CSS-in-JS libraries in your projects, you know exactly how and when to use it. Emotion can really help you to get to the next level and build more performative and scalable applications using CSS-in-JS.
In this article, we learned more about Emotion, a powerful and performant CSS-in-JS library that has a lot of nice features. We learned about the core of Emotion, we used the CSS
prop, and learned about theming.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowReact Native’s New Architecture offers significant performance advantages. In this article, you’ll explore synchronous and asynchronous rendering in React Native through practical use cases.
Build scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.