emotion Documentation

โ€๐ŸŽค CSS-in-JS library designed for high performance style composition

18,011 stars JavaScript JavaScript 1 file ยท ~9,579 tokens #babel-plugin#css#css-in-js#emotion#react#reactjs
RAW Doc

File: README.md

Emotion 11 has been released ๐Ÿš€ See the blog post



Emotion is a performant and flexible CSS-in-JS library. Building on many other CSS-in-JS libraries, it allows you to style apps quickly with string or object styles. It has predictable composition to avoid specificity issues with CSS. With source maps and labels, Emotion has a great developer experience and great performance with heavy caching in production.

[๐Ÿ‘€ Demo Sandbox](https://codesandbox.io/s/pk1qjqpw67)

[๐Ÿ“– Docs](https://emotion.sh/docs/introduction)

Frequently viewed docs:

Quick Start

Get up and running with a single import.

bash
npm install --save @emotion/react
jsx
/** @jsx jsx */
import { jsx } from '@emotion/react'

let SomeComponent = props => {
  return (
    
  )
}

Do I Need To Use the Babel Plugin?

The babel plugin is not required, but enables some optimizations and customizations that could be beneficial for your project.

Look here ๐Ÿ‘‰ emotion babel plugin feature table and documentation

Demo Sandbox

Demo Code Sandbox

Examples

Ecosystem

In the Wild

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]











Backers

Thank you to all our backers! ๐Ÿ™ [Become a backer]

Contributors

This project exists thanks to all the people who contribute. [Contribute].


File: docs/babel.mdx


title: 'Babel Plugin'

@emotion/babel-plugin is highly recommended. All of the options that can be provided to @emotion/babel-plugin are documented in @emotion/babel-plugin's README.

Install

In emotion version 8 and above, installation is optional. In older versions, installation is required. See the installation instructions.

Features which are enabled with the babel plugin

Minification

Any leading/trailing space between properties in your css and styled blocks is removed. This can reduce the size of your final bundle.

Dead Code Elimination

Uglifyjs will use the injected /*#__PURE__*/ flag comments to mark your css and styled blocks as candidates for dead code elimination.

Source Maps

When enabled, navigate directly to the style declaration in your javascript file.

Components as selectors

The ability to refer to another component to apply override styles depending on nesting context. Learn more in the styled docs.


File: docs/babel-macros.mdx


title: 'Babel Macros'

Create React App recently added support for Babel Macros which makes it possible to run Babel transforms without changing a Babel config.

All of Emotion's Babel Macros are available by adding /macro to the end of the import you'd normally use. (assuming you're using Create React App v2 or you've added babel-plugin-macros to your .babelrc) For example, to use the macro for styled, use @emotion/styled/macro.

jsx
import styled from '@emotion/styled/macro'
import { jsx, css, Global, keyframes } from '@emotion/react/macro'
import { css, keyframes, injectGlobal } from '@emotion/css/macro'

Note

There are some optimisations which aren't possible with Babel Macros, so if it's possible, we still recommend using @emotion/babel-plugin


File: docs/best-practices.mdx


title: 'Best Practices'

Emotion is an extremely flexible library, but this can make it intimidating, especially for new users. This guide contains several recommendations for how to use Emotion in your application. Keep in mind, these are only recommendations, not requirements!

Recommendations

Use TypeScript and object styles

You don't get Intellisense or type checking when using CSS strings, e.g. css`color: blue`. You can improve the developer experience and prevent style bugs by using TypeScript and object styles, which enable Intellisense and some static type checking:

tsx
const myCss = css({
  color: 'blue',
  grid: 1 // Error: Type 'number' is not assignable to type 'Grid | Grid[] | undefined'
})

Colocate styles with components

With normal CSS, the styles for a component are defined in a separate file. This makes maintenance more difficult because it's harder to tell which components use a given piece of CSS, and you can easily forget to update the relevant CSS after modifying a component. One of the main benefits of Emotion is that you can colocate your styles with your components. All this means is that the CSS for a component should be in the same file as the component itself.

Consider how you will share styles

There are two main approaches for sharing styles across an Emotion application.

To illustrate the two methods, let's imagine we're developing an application that needs to display error messages in many different components. All of the error messages should be red and bold. Some error messages should also use a large font.

Method 1: Export CSS objects

The simplest way to share styles is to export CSS from a shared file and then import that CSS in many places:

tsx
export const errorCss = css({
  color: 'red',
  fontWeight: 'bold'
})

// Use arrays to compose styles
export const largeErrorCss = css([errorCss, { fontSize: '1.5rem' }])

Then, in one of your components:

tsx
import { errorCss } from '...'

return Failed to fizzle the frozzle.

This method is great when you only want to share CSS between components. A potential drawback of this method is that shared styles are not colocated with the components that use them.

Method 2: Share styles via component reuse

This method is slightly more complex but arguably more powerful than the previous method.

tsx
export function ErrorMessage({ className, children }) {
  return (
    
      {children}
    
  )
}

// `fontSize: '1.5rem'` is passed down to the ErrorMessage component via the
// className prop, so ErrorMessage must accept a className prop for this to
// work!
export function LargeErrorMessage({ className, children }) {
  return (
    <ErrorMessage css={{ fontSize: '1.5rem' }} className={className}>
      {children}
    </ErrorMessage>
  )
}

Then, in one of your components:

tsx
import { ErrorMessage } from '...'

return <ErrorMessage>Failed to fizzle the frozzle.</ErrorMessage>

Advantages of sharing styles via component reuse include:

  • Component reuse allows you to share both logic and styles. You can easily add additional props and functionality to the ErrorMessage component with limited refactoring.
  • Styles are always colocated with their components.

Use the `style` prop for dynamic styles

The css prop or styled should be used for static styles, while the style prop (inline styles) should be used for truly dynamic styles. By dynamic styles, we mean styles that change frequently or are unique to a single element.

Imagine you are displaying a list of user avatars in a forum application. Every avatar shares certain static CSS, like width: 40px and border-radius: 50%, but the avatar image is set via a background-image rule whose value is different for each avatar. If you pass all of this CSS through the CSS prop, you'll end up with a lot of nearly-duplicate CSS in the document. With 3 avatars, Emotion will create something like:

html
<style>
  .css-1udhswa {
    border-radius: 50%;
    width: 40px;
    height: 40px;
    background-image: url(https://i.pravatar.cc/150?u=0);
  }

  .css-1cpwmbr {
    border-radius: 50%;
    width: 40px;
    height: 40px;
    background-image: url(https://i.pravatar.cc/150?u=1);
  }

  .css-am987o {
    border-radius: 50%;
    width: 40px;
    height: 40px;
    background-image: url(https://i.pravatar.cc/150?u=2);
  }
</style>

Now imagine how much CSS there would be if there were 100 avatars on the page!

You should also use the style prop if the styles will be updated frequently. If your application lets a user drag and drop an element, you likely have a transform property like

ts
{
  transform: `translate(${x}px, ${y}px)`
}

This property should go through the style prop since x and y will change rapidly as the element is dragged.

Advanced: CSS variables with `style`

CSS variables can be used with the style prop to keep the CSS in a single place while "deferring" the actual value of a property. Going back to the avatar example above, you could define the following static CSS using the css prop:

css
.avatar {
  border-radius: 50%;
  width: 40px;
  height: 40px;
  background-image: var(--background-image);
}

Then, for each avatar, you render an element which sets the value of the --background-image CSS variable:

tsx
function Avatar({ imageUrl }) {
  return 
}

If you're using TypeScript, you'll have to use a type assertion like style={{ ['--background-image' as any]: imageUrl }} as explained here.

If using React, prefer `@emotion/react` or `@emotion/styled` over `@emotion/css`

@emotion/react and @emotion/styled generally offer a better developer experience over class names (@emotion/css) when using React.

Use the css prop or `@emotion/styled`, but not both

While the css prop and styled can peacefully coexist, it's better to pick one approach and use it consistently across your codebase. Whether you choose the css prop or styled is a matter of personal preference. (If you're curious, the css prop is more popular among the maintainers of Emotion.)

Consider defining styles outside your components

For example:

tsx
import { css } from '@emotion/react'

const cardCss = {
  self: css({
    backgroundColor: 'white',
    border: '1px solid #eee',
    borderRadius: '0.5rem',
    padding: '1rem'
  }),

  title: css({
    fontSize: '1.25rem'
  })
}

export function Card({ title, children }) {
  return (
    
      <h5 css={cardCss.title}>{title}</h5>
      {children}
    
  )
}

Benefits of this approach:

  • Styles are only serialized once, instead of on every render.
  • It's no longer possible to accidentally pass dynamic styles through the css prop.
  • The JSX is arguably more readable with the CSS separated out into a different part of the file.

Define colors and other style constants as JavaScript variables

Don't repeat yourself! If you are using a color, padding, border radius, .etc throughout your application, add it to your theme or define it as a JavaScript constant, like

ts
export const colors = {
  primary: '#0d6efd',
  success: '#198754',
  danger: '#dc3545'
}

Don't use a theme unless your app supports multiple themes (or will eventually support multiple themes)

Emotion allows you to define a theme which you can use in style rules across your application. This feature is awesome if your app has multiple themes, like light mode and dark mode.

On the other hand, if your app will only ever have a single theme, it's simpler to define colors and other style variables as JavaScript constants.

Additional Reading


File: docs/cache-provider.mdx


title: 'CacheProvider'

It can be useful to customize emotion's options - i.e. to add custom Stylis plugins, customize prefix of inserted class names, render style tags into specific element and more. You can look up full list of options here.

jsx
// @live
import { CacheProvider, css } from '@emotion/react'
import createCache from '@emotion/cache'
import { prefixer } from 'stylis'

const customPlugin = () => {}

const myCache = createCache({
  key: 'my-prefix-key',
  stylisPlugins: [
    customPlugin,
    // has to be included manually when customizing `stylisPlugins` if you want
    // to have vendor prefixes added automatically
    prefixer
  ]
})

render(
  <CacheProvider value={myCache}>
    
      
        Some text
      
    
  </CacheProvider>
)

File: docs/class-names.mdx


title: 'Class Names'

It can be useful to create a className that is not passed to a component, for example if a component accepts a wrapperClassName prop or similar. To do this, Emotion exposes a render prop component which you can pass a function which accepts css and cx. If you have used versions of Emotion prior to Emotion 10 or used vanilla Emotion, the css and cx functions work exactly like they do in those versions.

jsx
// @live
import { ClassNames } from '@emotion/react'

// this might be a component from npm that accepts a wrapperClassName prop
let SomeComponent = props => (
  
    in the wrapper!
    {props.children}
  
)

render(
  <ClassNames>
    {({ css, cx }) => (
      <SomeComponent
        wrapperClassName={css({ color: 'green' })}
        className={css`
          color: hotpink;
        `}
      >
        from children!!
      </SomeComponent>
    )}
  </ClassNames>
)

File: docs/community.mdx


title: 'Community'

A curated list of awesome stuff related to Emotion.

Contents

Libraries

Component Libraries

Examples In the Wild


File: docs/composition.mdx


title: 'Composition'

Composition is one of the most powerful and useful patterns in Emotion. You can compose styles together by interpolating value returned from css in another style block.

jsx
// @live
import { css } from '@emotion/react'

const base = css`
  color: hotpink;
`

render(
  
    This is hotpink.
  
)

With regular css, you can compose styles together using multiple class names, but this is very limited because the order that they're defined is the order they'll be applied. This can lead to hacks with !important and such to apply the correct styles.

For example, we have some base styles and a danger style, we want the danger styles to have precedence over the base styles but because base is in the stylesheet after danger its styles will override the styles defined in danger, as per the cascade rules. In regular CSS, you might do something to make danger take precedence over base like moving the danger class so it's defined later than base, or use !important, or abandon composition and rewrite the styles each time you need them.

jsx
// @live
render(
  
    <style>
      {`
        .danger {
          color: red;
        }
        .base {
          background-color: lightgray;
          color: turquoise;
        }
      `}
      >
    </style>
    What color will this be?
  
)

With Emotion though, you can create styles and combine them.

jsx
// @live
import { css } from '@emotion/react'

const danger = css`
  color: red;
`

const base = css`
  background-color: darkgreen;
  color: turquoise;
`

render(
  
    This will be turquoise
    
      This will be also be turquoise since the base styles overwrite the danger
      styles.
    
    This will be red
  
)

Using Emotion's composition, you don't have to think about the order that styles were created because the styles are merged in the order that you use them.


File: docs/css-prop.mdx


title: 'The css Prop'

The primary way to style elements with emotion is the css prop. It provides a concise and flexible API to style your components.

Get Started

There are 2 ways to get started with the css prop.

Both methods result in the same compiled code.
After adding the preset or setting the pragma as a comment, compiled jsx code will use emotion's jsx function instead of React.createElement.

Input Output
Before `` React.createElement('img', { src: 'avatar.png' })
After `` jsx('img', { src: 'avatar.png' })

Babel Preset

This method will not work with Create React App or other projects that do not allow custom Babel configurations.
Use the JSX Pragma method instead.

.babelrc

json
{
  "presets": ["@emotion/babel-preset-css-prop"]
}

Full @emotion/babel-preset-css-prop documentation

If you are using the compatible React version (>=16.14.0) then you can opt into using the new JSX runtimes by using such configuration:

.babelrc

json
{
  "presets": [
    [
      "@babel/preset-react",
      { "runtime": "automatic", "importSource": "@emotion/react" }
    ]
  ],
  "plugins": ["@emotion/babel-plugin"]
}

In case you want to use the new JSX runtimes with Next.js and you are using their next/babel preset then the configuration should look like this:

.babelrc

json
{
  "presets": [
    [
      "next/babel",
      {
        "preset-react": {
          "runtime": "automatic",
          "importSource": "@emotion/react"
        }
      }
    ]
  ],
  "plugins": ["@emotion/babel-plugin"]
}

JSX Pragma

Set the jsx pragma at the top of your source file that uses the css prop.
This option works best for testing out the css prop feature or in projects where the babel configuration is not configurable (create-react-app, codesandbox, etc.).

js
/** @jsx jsx */

Similar to a comment containing linter configuration, this configures the jsx babel plugin to use the jsx function instead of React.createElement.

If you are using a zero-config tool with automatic detection of which runtime (classic vs. automatic) should be used and you are already using a React version that has the new JSX runtimes (hence runtime: 'automatic' being configured automatically for you) such as Create React App 4 then /** @jsx jsx */ pragma might not work and you should use /** @jsxImportSource @emotion/react */ instead.

JSX Pragma Babel Documentation

Import the `jsx` function from `@emotion/react`

js
/** @jsx jsx */
import { jsx } from '@emotion/react'

Note that excluding this will cause your css to render as [Object Object].

Use the `css` prop

Any component or element that accepts a className prop can also use the css prop. The styles supplied to the css prop are evaluated and the computed class name is applied to the className prop.

Object Styles

The css prop accepts object styles directly and does not require an additional import.

jsx
// @live
render(
  
    This has a hotpink background.
  
)

Object Style Documentation.

String Styles

To pass string styles, you must use css which is exported by @emotion/react, it can be used as a tagged template literal like below.

jsx
// @live
import { css } from '@emotion/react'

const color = 'darkgreen'

render(
  
    This has a hotpink background.
  
)

Note:

css from @emotion/react does not return the computed class name string. The function returns an object containing the computed name and flattened styles. The returned object is understood by emotion at a low level and can be composed with other emotion based styles inside of the css prop, other css calls, or the styled API.

You can also pass in your css as variables, which allows for composition (read more about this here).

Style Precedence

  • Class names containing emotion styles from the className prop override css prop styles.
  • Class names from sources other than emotion are ignored and appended to the computed emotion class name.

The precedence order may seem counter-intuitive, but it allows components with styles defined on the css prop to be customized via the className prop passed from the parent.

The P component in this example has its default styles overridden in the ArticleText component.

jsx
const P = props => (
  
)

const ArticleText = props => (
  
)

The ArticleText component can be customized and the styles composed with its default styles. The result is passed P and the process repeats.

jsx
const P = props => (
  
)

const ArticleText = props => (
  
)

const SmallArticleText = props => (
  <ArticleText
    css={{
      fontSize: 10
    }}
    {...props} // <- props contains the `className` prop
  />
)

The styles are concatenated together and inserted via insertRule.

  1. P component
css
.css-1 {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  font-family: sans-serif;
  color: black;
}
  1. ArticleText component
css
.css-2 {
  font-size: 14px;
  font-family: Georgia, serif;
  color: darkgray;
}
  1. SmallArticleText component
css
.css-3 {
  font-size: 10px;
}
  1. Result
diff
.css-result {
+ margin: 0;
- font-size: 12px;
+ line-height: 1.5;
- font-family: 'sans-serif';
- color: black;
- font-size: 14px;
+ font-family: Georgia, serif;
+ color: darkgray;
+ font-size: 10px;
}

Relying on the css spec's "Order of Appearance" rule, property values defined later (green) override those before it (red).

Gotchas

  • If you include the plugin @babel/plugin-transform-react-inline-elements in your .babelrc your styles will not be applied. The plugin is not compatible with the css prop.
  • When using React.cloneElement you can't easily add a css prop if the cloned element doesn't already have it. Otherwise React.cloneElement works with jsx-created elements.

File: docs/emotion-11.mdx


title: 'Emotion 11'

Emotion 11 is a slight evolution over the Emotion 10. It focuses mainly on the developer experience, TS types improvements, switches internals to hooks and to the new version of the parser that we use: Stylis.

Package renaming

One of the most significant changes is that most of the user-facing packages have been renamed.

Most of this renaming can be done automatically via a codemod, following these steps:

  1. Install @emotion/eslint-plugin
  2. Add it as a plugin to .eslintrc
  3. Add Emotion 11 codemod rule
  4. Run eslint with the --fix flag. For example: yarn eslint --config .eslintrc --ext .js,.jsx "." --fix

The full list of renamed packages:

  • @emotion/core โ†’ @emotion/react
  • emotion โ†’ @emotion/css
  • emotion-theming โ†’ moved into @emotion/react
  • emotion-server โ†’ @emotion/server
  • create-emotion โ†’ @emotion/css/create-instance
  • create-emotion-server โ†’ @emotion/server/create-instance
  • babel-plugin-emotion โ†’ @emotion/babel-plugin
  • eslint-plugin-emotion โ†’ @emotion/eslint-plugin
  • jest-emotion โ†’ @emotion/jest

Hooks

Use hooks internally for improved bundle size and a better tree in React DevTools ๐ŸŽ‰.

TypeScript

Types overhaul

TypeScript types have been significantly restructured.

  • reduce build times when using Emotion, especially in larger projects
  • it's no longer necessary to manually specify generic parameters for your Emotion components in many cases
  • union types as props are better supported and should be inferred properly
  • the css function has been restricted to prevent passing invalid types
  • styled's generic parameter has been changed, if you were specifying the ComponentType you will need to remove that generic parameter
  • styled no longer takes a second ExtraProps parameter - instead of that move it to after the styled call. So instead of writing styled<typeof MyComponent, ExtraProps>(MyComponent)({}) you should now be writing styled(MyComponent)<ExtraProps>({})

If you encounter build issues after upgrade, try removing any manually specified generic types and let them be inferred.

Theme type

It's now easier to provide a type for Theme. Instead of creating custom instances (like before) you can augment the builtin Theme interface like this:

ts
import '@emotion/react'

declare module '@emotion/react' {
  export interface Theme {
    primaryColor: string
    secondaryColor: string
  }
}

css prop types

The way in which we provide TypeScript support for the css prop has changed. Based on the usage of our JSX factories, we can add support for css prop only for components that support className prop (as our JSX factory functions take the provided css prop, resolve it and pass the generated className to the rendered component).

For the classic runtime this has been implemented using technique described here. What is important - we no longer extend any global interfaces, so people shouldn't bump anymore into type conflicts for the css prop when using different libraries with css prop support, such as styled-components.

For the automatic runtime this has been implemented by exporting JSX namespace from the appropriate entries but this is only supported in TypeScript 4.1 or higher.

However, if you are stuck with older version of TypeScript or using the classic runtime implicitly by using our @emotion/babel-preset-css-prop then it's not possible to leverage css prop support being added conditionally based on a type of rendered component. For those cases we have added a special file that can be imported once to add support for the css prop globally, for all components. Use it like this:

ts
/// <reference types="@emotion/react/types/css-prop" />

In this particular case we are forced to extend the existing React.Attributes interface. Previously we've been extending both React.DOMAttributes and JSX.IntrinsicAttributes. This change is really minor and shouldn't affect any consuming code.

Stylis v4

The parser we use (Stylis) got upgraded. It fixes some long-standing parsing edge cases while being smaller and faster ๐Ÿš€

It has been completely rewritten and comes with some breaking changes. The most notable ones that might affect Emotion users are:

  • plugins written for the former Stylis v3 are not compatible with the new version. To learn more on how to write a plugin for Stylis v4 you can check out its README and the source code of core plugins.
  • vendor-prefixing was previously customizable using prefix option. This was always limited to turning off all of some of the prefixes as all available prefixes were on by default. The prefix option is gone and to customize which prefixes are applied you need to fork (copy-paste) the prefixer plugin and adjust it to your needs. While this being somewhat more problematic to setup at first we believe that the vast majority of users were not customizing this anyway. By not including the possibility to customize this through an extra option the final solution is more performant because there is no extra overhead of checking if a particular property should be prefixed or not.
  • the prefixer is now just a plugin which happens to be included in the default stylisPlugins. If you plan to use custom stylisPlugins and you want to have your styles prefixed automatically you must include prefixer in your custom stylisPlugins. You can import prefixer from the stylis module to do that.
  • @import rules are no longer special-cased. The responsibility to put them first has been moved to the author of the styles. They also can't be nested within other rules now. It's only possible to write them at the top level of global styles.

Emotion's caches

The key option is now required when creating a custom instance of a cache. Please make sure it's unique (and not equal to 'css') as it's used for linking styles to your cache. If multiple caches share the same key they might "fight" for each other's style elements.

The new prepend option can make Emotion add style tags at the beginning of the specified DOM container instead of the end.

Other

There are a lot of less substantial changes than what has been described here, some of them might even be breaking changes but are not relevant to the majority of users. Therefore to learn more about all of the changes please read through the full list of changes contained in the respective changelogs:

@emotion/babel-plugin
@emotion/babel-preset-css-prop
@emotion/cache
@emotion/css
@emotion/eslint-plugin
@emotion/is-prop-valid
@emotion/jest
@emotion/native
@emotion/primitives-core
@emotion/primitives
@emotion/react
@emotion/serialize
@emotion/server
@emotion/sheet
@emotion/styled
@emotion/utils