πŸ‡ΊπŸ‡¦ STOP WAR IN UKRAINE πŸ‡ΊπŸ‡¦
Avatar

Emotion

Migrating to Emotion 10

✏️ Edit this page

Emotion 10 is a significant change to Emotion, so it requires some changes to your code. Some of the changes can be done automatically via a codemod, and the rest can be done incrementally.

Note

This page only applies if you're using Emotion with React. If you're not using Emotion with React, you don't have to change anything.

Note

Emotion 10 requires React 16.3 or greater.

Thinking

The most significant change in Emotion 10 is that it doesn't let you easily access the underlying class names. Instead of thinking in class names, you have to think in terms of styles and composing them together (you can still use class names directly if you want to, but you won't get new features like zero-config server rendering).

For example, in Emotion 9, you might have had two classes from css and compose them together with cx, but in Emotion 10, you create two styles and compose them together in the css prop like this:

// Emotion 9
import { css, cx } from 'emotion'

let basic = css`
  color: green;
`

let important = css`
  color: hotpink;
`

const SomeComponent = props => (
  <div className={cx(basic, props.important && important)} />
)
// Emotion 10
/** @jsx jsx */
import { css, jsx } from '@emotion/core'

let basic = css`
  color: green;
`

let important = css`
  color: hotpink;
`

const SomeComponent = props => (
  <div css={[basic, props.important && important]} />
)

Incremental Migration

Incremental migration is something really important to Emotion because we don't want anyone to have to rewrite their entire app.

The upgrades to Emotion 10 are split into two parts. The first part can be done automatically by using eslint-plugin-emotion.

Codemoddable

  • Change all react-emotion imports so that styled is imported from @emotion/styled and all the emotion exports are split into a second import.
import styled, { css } from 'react-emotion'

// ↓ ↓ ↓ ↓ ↓ ↓

import styled from '@emotion/styled'
import { css } from 'emotion'
  • Add a css call to the css prop when a template literal is used.
let element = (
  <div
    css={`
      color: hotpink;
    `}
  />
)

// ↓ ↓ ↓ ↓ ↓ ↓

import { css } from '@emotion/core'

let element = (
  <div
    css={css`
      color: hotpink;
    `}
  />
)
  • Add a jsx import and set the jsx pragma at the top of the source file.
import { css } from '@emotion/core'

let element = (
  <div
    css={css`
      color: hotpink;
    `}
  />
)

// ↓ ↓ ↓ ↓ ↓ ↓

/** @jsx jsx */
import { css, jsx } from '@emotion/core'

let element = (
  <div
    css={css`
      color: hotpink;
    `}
  />
)

Manual Steps

  • Add compat cache with provider

This step is necessary if you still use css, keyframes or injectGlobal from emotion. Once you remove all the usages of them in your app, you can remove this.

import { render } from 'react-dom'
import App from './App'
import { cache } from 'emotion'
import { CacheProvider } from '@emotion/core'

render(
  <CacheProvider value={cache}>
    <App />
  </CacheProvider>,
  rootNode
)

Manual Steps Over Time

  • Change css usage to css prop
import { css } from 'emotion'
let element = (
  <div
    className={css`
      color: hotpink;
    `}
  />
)

// ↓ ↓ ↓ ↓ ↓ ↓

/** @jsx jsx */
import { jsx, css } from '@emotion/core'

let element = (
  <div
    css={css`
      color: hotpink;
    `}
  />
)

If you have components that accepts props like wrapperClassName, etc., you can use the ClassNames component.

import { css } from 'emotion'
import { SomeComponent } from 'somewhere'
let element = (
  <SomeComponent
    wrapperClassName={css`
      color: hotpink;
    `}
  />
)

// ↓ ↓ ↓ ↓ ↓ ↓

import { ClassNames } from '@emotion/core'
import { SomeComponent } from 'somewhere'

let element = (
  <ClassNames>
    {({ css }) => (
      <SomeComponent
        wrapperClassName={css`
          color: hotpink;
        `}
      />
    )}
  </ClassNames>
)
  • Replace injectGlobal with Global styles
import { injectGlobal } from 'emotion'

injectGlobal`
  * {
    box-sizing: border-box;
  }
`

// ↓ ↓ ↓ ↓ ↓ ↓

import { Global, css } from '@emotion/core'

;<Global
  styles={css`
    * {
      box-sizing: border-box;
    }
  `}
/>