DEV Community

Cover image for Emotion in React
Brian Neville-O'Neill for LogRocket

Posted on • Originally published at blog.logrocket.com on

Emotion in React

Written by Leonardo Maldonado✏️

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.

LogRocket Free Trial Banner

Emotion

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.

Performance

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.

Framework agnostic

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
Enter fullscreen mode Exit fullscreen mode

No additional set up

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
Enter fullscreen mode Exit fullscreen mode

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>
)
Enter fullscreen mode Exit fullscreen mode

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.

Styling

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

CSS prop

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"]
}
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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>
  )
};
Enter fullscreen mode Exit fullscreen mode

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>
  )
};
Enter fullscreen mode Exit fullscreen mode

Style API

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
Enter fullscreen mode Exit fullscreen mode

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;
`;
Enter fullscreen mode Exit fullscreen mode

Theming

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
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

Media queries

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];
Enter fullscreen mode Exit fullscreen mode

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)`;
Enter fullscreen mode Exit fullscreen mode

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;
  }
`;
Enter fullscreen mode Exit fullscreen mode

SSR by default

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 />)
Enter fullscreen mode Exit fullscreen mode

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>`);
Enter fullscreen mode Exit fullscreen mode

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')
);
Enter fullscreen mode Exit fullscreen mode

Should I use Emotion?

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.

Conclusion

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.


LogRocket: Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

Alt Text

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — start monitoring for free.


The post Emotion in React appeared first on LogRocket Blog.

Top comments (0)