Replacing Styled Components with a 1KB alternative Goober
Tags: react, javascript, cssinjs, goober
Published: 2020-02-12 19:46:37

[Styled Components](https://www.styled-components.com/) and [EmotionJS](https://emotion.sh/) are two of the most popular CSS-in-JS libraries for the React land. But both of these do come with a cost, anywhere between 10KB to 20KB is how much any of these libraries would add to the your bundle.

What if we could replace the same with a 1KB library? That is the promise of [GooberJS](https://github.com/cristianbote/goober) that uses the same `styled(element)` paradigm styled-components and emotion popularised but at much lesser size.

Goober does this by utilising a [custom pragma pattern](https://www.gatsbyjs.org/blog/2019-08-02-what-is-jsx-pragma/) which is already used in cases like the [`css` prop in emotion](https://emotion.sh/docs/css-prop#jsx-pragma) or [`sx` prop in ThemeUI](https://theme-ui.com/guides/jsx-pragma/).

> TLDR; JSX Pragma is a way of customising how JSX is compiled to React elements (`React.createElement`) and adding our own thing in there.

## Installation

You can install GooberJS with npm or yarn:

```bash
npm install goober
# or
yarn add goober
```

## Usage

First, we have to set the pragma to match:

```js
import { createElement } from 'react';
import { setPragma } from 'goober';

setPragma(createElement);
```

Note that this has to be performed only once in the whole application and would probably go in `index.js` file in your application.

### How do I styled an HTML element?

```jsx
// It's a named export
import { styled } from 'goober';

// Notice the parathesis.
const Title = styled('h1')`
  font-size: 2rem;
  color: maroon;
`;

function Header() {
  return (
    <header>
      <Title>Goober</Title>
    </header>
  );
}
```

Goober also supports nesting and SASS like `&:hover` kind pseudo selectors as it's predecessors. You can also add media templates inside styled components to make it work.

## How do I customise it with props?

```jsx
import { styled } from 'goober';

const Title = styled('h1')`
  font-size: 2rem;
  color: ${props => props.textColor};
`;

function Header() {
  return (
    <header>
      <Title textColor="red">Goober</Title>
    </header>
  );
}
```

## How do I extend a component?

```jsx
import { styled } from 'goober';

const Title = styled('h1')`
  font-size: 2rem;
  color: ${props => props.textColor};
`;

const LargeTitle = styled(Title)`
  font-size: 4rem;
`;

function Header() {
  return (
    <header>
      <Title textColor="red">Goober</Title>
    </header>
  );
}
```

## Global Styles?

Goober exposes `glob` function for this. It is not to be imported/used anywhere else, just using this function would add the global styles as necessary.

```jsx
import { glob } from 'goober';

glob`
  body {
    margin: 0;
  }
`;
```

I do feel that styled components API did it better here with the `createGlobalStyle` function. But if you have been with the project for long, you will know this is how it started off.

## Missing `styled.tag`?

If you are feeling attached to `styled.tag` format from Styled Components, Goober team has a babel plugin that can help so that you can keep writing `styled.tag` but the plugin will convert the references for you.

```bash
npm i --save-dev babel-plugin-transform-goober
# or
yarn add --dev babel-plugin-transform-goober
```

# What's pending now?

- Goober does not automatically vendor prefix styles as of now, but they are proactively working on it.
- Goober does not support theming at the moment. [Here is the PR](https://github.com/cristianbote/goober/pull/76) they are working on.

But this should not discourage you from using theming at all. You can always fallback to using CSS variables (or create a Theme Context and work with it if you miss JavaScript theming)

Here is a kitchen sink of everything mentioned in this article: 

{% codesandbox react-goober-lc4g6 %}