Scoped CSS for React Components with TypeScript
Tags: react, css
Published: 2021-05-25 08:17:54

---
title: Scoped CSS for React Components with TypeScript
published: true
description: Why and how you can use Scoped CSS for your React Components
tags: react, css,
cover_image: https://images.unsplash.com/photo-1551742455-a1f7f4033067?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1567&q=80
---

React applications are being composed of small components that can be used individually and in best case scenario can be reused across multiple applications. But what about the CSS that they need for layouting elements inside them?

Often you end up inventing a system for it, something like that: you group CSS rules by a class name for each component and everything that is specific to a component goes in there. It's a start but it's not perfect. Soon you start renaming stuff or you want to apply styles from a global perspective.

Coming from the Vue.js world, I especially liked the approach of [Single File Components](https://vuejs.org/v2/guide/single-file-components.html) - everything that belongs to that component goes into one file, CSS, HTML and JavaScript or TypeScript and I wanted to have this in React too, so I took of into the world of CSS-in-JS.

## CSS Modules

I came to React, looking for Single File Components all over the place and as it turns out, it's not that easy 😔 What I did find though, is [CSS Modules](https://github.com/css-modules/css-modules) 🥳
It works like this: you import the CSS as a JavaScript module , which have been mapped from your CSS class names and assign those as `className` properties in the JSX. I used the npm package `typescript-plugin-css-modules` for this. This is how a Component styled with it looks like:

```tsx
import styles from "./foo.css";

const FooComponent = () => {
  return <div className={styles.myClassName}>Hello, World!</div>;
};
```

I still wasn't satisfied with this approach as there were still two files to edit when the component needs to be modified. Then I learned about [Emotion](https://emotion.sh/) in [Jason Lengstorf](https://twitter.com/jlengstorf?)'s [Introduction to Gatsby](https://frontendmasters.com/courses/gatsby/) course on Frontend Masters and it was exactly what I was looking for. I was intruiged 😁

## Emotion to the rescue

To style React components with emotion, there are several options to choose from depending on your preferences and what you want to achieve. The one I like most as a starting point, is using the `css`-template string helper that lets you write CSS like you would in a CSS file. This is a sample component using it to set a `width`, `height` and `background-color`:

```tsx
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
import React from "react";

function Card() {
  return (
    <div
      css={css`
        width: 100px;
        height: 100px;
        background-color: red;
      `}
    >
      using the css template string helper
    </div>
  );
}

export default Card;
```

Really simple, huh? The first line `/** @jsxImportSource @emotion/react */` tells the TypeScript compiler, how to resolve the css helper and it took me quite a while to figure it out!

But it can get quite messy when the component grows and contains more tags than just this one div. For this occasion, you can refactor the component and use styled components like this:

```tsx
import styled from "@emotion/styled";

const ListItem = styled("li")`
  font-weight: bold;
`;

interface ListProps {
  items: Array<string>;
}

function List({ items }: ListProps) {
  return (
    <ul>
      {items.map((item) => (
        <ListItem key={item}>{item}</ListItem>
      ))}
    </ul>
  );
}

export default List;
```

As you can see, `ListItem` uses the `styled` function to create a styled component that only adds CSS to a `li` element and automatically renders its children in it.

Now I got to the point where I was satisfied. At least until I realized that I wanted to have kind of like a theming, where I would store colors, definitions of borders and such things that I would need over and over again in a central location. Emotion provides a Theming API, why not try that?

## Theming

To start with the theme, I implemented a new class for it and created a new instance of it:

```ts
class Theme {
  readonly primaryColor: string = "green";
}

const theme = new Theme();
```

Theming then works like this: you provide the Theme to your components using a `<ThemeProvider>` and access the theme in the actual component using the `useTheme` hook provided by ` @emotion/react`. Here's my App, that does exactly that:

```tsx
import { ThemeProvider } from "@emotion/react";

function App() {
  return (
    <div>
      <ThemeProvider theme={theme}>
        <MyComponentWithTheme />
      </ThemeProvider>
    </div>
  );
}
```

And here is `MyComponentWithTheme`, which uses both the Theme and the `css` template string helper:

```tsx
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
import { useTheme } from "@emotion/react";
import { Theme } from "../App";

function ComponentWithTheme() {
  const theme = useTheme() as Theme;

  return (
    <div
      css={css`
        width: 100px;
        height: 100px;
        background: ${theme.primaryColor};
      `}
    >
      Component using the Theme provided in App
    </div>
  );
}

export default ComponentWithTheme;
```

Using that, I found a way to write the CSS I need for my components directly in the components. I still need to figure out what parts of the style sheets go into a component or into a global style sheet, but it's a start.

Of course emotion does a lot more than that (like adding vendor prefixes and stuff) but I am still learning about it and find it very interesting and fun. I am looking forward for your tips and tricks around emotion and CSS-in-JS in common!