DEV Community

Cover image for Replacing Styled Components with a 1KB alternative Goober
Agney Menon
Agney Menon

Posted on • Originally published at blog.agney.dev

Replacing Styled Components with a 1KB alternative Goober

Styled Components and EmotionJS 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 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 which is already used in cases like the css prop in emotion or sx prop in ThemeUI.

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:

npm install goober
# or
yarn add goober

Usage

First, we have to set the pragma to match:

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?

// 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?

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?

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.

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.

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 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:

Top comments (6)

Collapse
 
ben profile image
Ben Halpern

Neat! I'm a huge fan of the 1kb alternative to genre of JS libs.

Collapse
 
cristianbote profile image
Cristian Bote

Thank you @boywithsilverwings ! :) I appreciate the article and taking the time to write it! This is awesome! :D I'm so excited that I'll jump on the theme PR and hopefully I can have it under 1kb cause that's all that's left. But, that's what drives me and gooberπŸ₯œ!

Collapse
 
manueldev profile image
ManuelDev

Awesome, really awesome πŸ‘πŸ‘πŸ‘πŸ‘

Collapse
 
barzi92367868 profile image
Barzi

I will definitely give it a try!
Thanks!

Collapse
 
pretaporter profile image
Maksim

Cool stuff! Is it supports TypeScript?

Collapse
 
cristianbote profile image
Cristian Bote

Yup! And that's because of our great community effort. It's been really awesome to see it happen!