CSS in JS (part 2)
Tags: javascript, css, react, frontend
Published: 2019-08-21 07:58:51

---
title: CSS in JS (part 2)
published: true
tags: javascript, css, react, frontend
canonical_url: https://hellocode.dev/css-in-js-2
cover_image: https://www.nps.gov/articles/images/Art_1.jpg?maxwidth=1200&autorotate=false
---

In my [last blog post](https://dev.to/thorning_m/css-in-js-il) I wrote about how I had started using [Emotion](https://github.com/emotion-js/emotion) instead of Sass. Initially I was using Emotion's framework-agnostic package, but I have now switched to using the version which they created specifically for use with React because it adds some extra functionality which I liked the look of! This post is going to be about using Emotion with React, because of that, I'm going to be making the assumption that if you're reading this then you already know how to use React.

Let's get started, you can install the package with NPM:

```
npm install @emotion/core --save-dev
```

Then you will need to make some changes to your Babel setting to enable your project to work with this package.

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>Babel

There are two methods available for making your app work with _@emotion/core_. The quickest way is to import Emotion's `jsx` function at the top of your file and include a [JSX Pragma](https://emotion.sh/docs/css-prop#jsx-pragma) on the line above it like so:

```js
/** @jsx jsx */
import { jsx } from '@emotion/core'
```

The pragma (which is the bit in comments) tells Babel to use Emotion's `jsx` function in place of React's _createElement_. With these lines in your imports you will be able to use the _css_ prop anywhere in your file that you may have previously used _className_. This is a good solution if you just want to try it out or if you don't have access to your Babel settings, it is a bit of a pain having to do this in every file though so if possible I recommend using the second method which is to add the Babel preset. This is easy to do, just install it with NPM and then include it in your _.babelrc_ or _babel.config.js_:

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

If you're using Gatsby (as I am for this site) there is a [plugin](https://www.gatsbyjs.org/packages/gatsby-plugin-emotion/) you can use instead.

Once you've set up the Babel preset you no longer need to include the pragma or import the _jsx_ function at the top of your files, every component in you codebase will now be able to use the _css_ prop.

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>The css prop

The _css_ prop accepts your styles in several ways which gives you some added flexibility when writing your components.

It will accept object styles:

```js
const styles = {
  color: 'red',
  marginTop: '10px'
}

export default function HelloCode(props) {
  return <h1 css={styles}>Hello Code</h1>
}
```

It will also accept string styles which have been created with _@emotion/core_'s `css` function:

```js
import { css } from '@emotion/core'

const styles = css`
  color: red;
  margin-top: 10px;
`
export default function HelloCode(props) {
  return <h1 css={styles}>Hello Code</h1>
}
```

Unlike with the _css_ function in the framework-agnostic version, _this_ `css` function does not return a computed class name string; it returns an object which Emotion understands 'at a low level' and as such can be composed with other Emotion based styles. Therefore, it is important that you don't try to use the _css_ function which is exported by the framework-agnostic version of Emotion.

You can also pass an array of styles to the `css` prop. The styles are applied left-to-right with any duplicated rules being overridden:

```js
import { css } from '@emotion/core'

const blue = css`
  color: blue;
  margin-top: 10px;
`
const red = css`
  color: red;
`
export default function HelloCode(props) {
  return <h1 css={[blue, red]}>Hello Code</h1>
}
//Text will be red
```

This is great for controlling your styling through the logic of your component using its state or props. In the example below I have used a reducer with React's `useReducer` and `useEffect` hooks to add a class to the component five seconds after the component mounts:

```js
import React, { useEffect, useReducer } from 'react'
import { baseStyle, animationStyle } from './style'

export default function HelloCode() {

  const reducer = (state, action) => {
    switch (action.type) {
      case 'addClass':
        return {
          style: [...state.style, action.payload],
        }
      default:
        return state
    }
  }

  const initialState = {
    style: [baseStyle]
  }

  const [state, dispatch] = useReducer(reducer, initialState)

  function animate() {
    setTimeout(() => {
      dispatch({
        type: 'addClass',
        payload: animationStyle,
      })
    }, 5000)
  }

  useEffect(() => {
    animate()
  }, [])

  return <h1 css={state.style}>Hello Code</h1>
}
```

So you can see that `useEffect` calls the `animate` function on component mount. This function uses `setTimeout` to dispatch the `addClass` action after a `5000` milliseconds delay. The payload of the action contains the reference to the `animationStyle` which is imported at the top of the file. The reducer matches the action type with `addClass` and updates the component's state with a new array containing both `state.style` and `animationStyle` from `action.payload`.

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>The Global component

I generally believe it's a good idea to keep your CSS styles scoped to your components. When writing React applications you build up from the smallest level of granularity; creating one large stylesheet which controls styling for the entire app flies in the face of this methodolgy (in my opinion). However, it's still important to maintain consistency in the way the UI looks across your application. There are two options available to help with this, here is the first.

_@emotion/core_ provides a `Global` component which can be utilised to apply CSS rules globally to your site. It's used like this:

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

export default function HelloCode() {
  return (
    <div>
      <Global
        styles={css`
          h1 {
            color: red;
          }
        `}
      />
      <h1>Hello Code</h1>
    </div>
  )
}
```

This is interesting because you can completely change the styling of your site just by rendering a `Global` component. One of React's strengths is that it makes conditionally rendering child components effortless, using the `Global` component as a child you could very easily change the entire look of your site with the push of a button:

```js
import React, { useState } from 'react'
import { Global, css } from '@emotion/core'

const nightModeStyle = css`
  body {
    background: black;
  }
  h1 {
    color: white;
  }
`
export default function HelloCode() {
  const [nightMode, setNightMode] = useState(false)

  return (
    <div>
      {nightMode && <Global styles={nightModeStyle} />}
      <button onClick={() => setNightMode(!nightMode)}>Night Mode</button>
      <h1>Hello Code</h1>
    </div>
  )
}
```

Slight disclaimer with this one, I haven't tried it (yet); if you happen to try it and it doesn't work then let me know!

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>Theming

With theming you can create an object containing settings that you want to have access to in the _css_ prop of any component. This is great for maintaining a consistent look and makes changing colours for branding a lot easier because you only need to change the values in one place instead of in every component.

If you want to use theming with Emotion then you wil first need to install it with NPM:

```
npm install emotion-theming --save-dev
```

_emotion-theming_ uses React's context API, so first you need to wrap all of the components which you want to have access to the theme in the `ThemeProvider`. This is standard context stuff, only instead of a _value_ prop it uses `theme`:

```js
import { render } from 'react-dom'
import App from './app'
import { ThemeProvider } from 'emotion-theming'

const theme = {
  primaryTextColor: 'red'
  h1TopMargin: '10px'
}

render(
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>,
  document.getElementById('root')
)
```

Now, let's take an example from earlier on but this time we'll get the values from the theme:

```js
import { css } from '@emotion/core'

const styles = theme => css`
  color: ${theme.primaryTextColor};
  margin-top: ${theme.h1TopMargin};
`
export default function HelloCode(props) {
  return <h1 css={styles}>Hello Code</h1>
}
```

The `css` prop also accepts a function which is called with the `theme` as an argument. When React sees this it walks back up the components tree until it finds a `ThemeProvider` and gets the theme object from its prop. Because this is a JavaScript object it can be passed around as you would any other object. Here's another example from earlier:

```js
import { css } from '@emotion/core'

const blue = theme => css`
  color: blue;
  margin-top: ${theme.h1TopMargin};
`
const red = theme => css`
  color: ${theme.primaryTextColor};
`
export default function HelloCode(props) {
  return (
    <h1 css={theme => (
      [blue, red].map(style => style(theme))
    )}>
      Hello Code
    </h1>
  )
}
//Text will be red
```

Here we are passing the theme object to each function in the array using map. I'm sure you can see how powerful this can be; any `css` prop can very easily be turned into a function with access to everything in your theme object just by prepending it with `theme =>`!

* * *

That's covered everything I've been doing with Emotion lately. There's more in their documentation which I haven't covered but I've talked about the stuff which I've found the most useful. Still, take a look and if you see or know of anything that I've not mentioned which you think is useful then please let me know. Cheers! 👍