# goober: Sub-1 KB CSS-in-JS with a Familiar Styled-Components API

> goober is a CSS-in-JS library with a base bundle size of 1.25 KB, offering the styled template-literal API, SSR via extractCss, theming, and global styles at a fraction of the weight of styled-components or emotion. It trades away debug labels, the .attrs API, and the .withComponent method to achieve that size.

**cristianbote/goober** — 🥜 goober, a less than 1KB 🎉  css-in-js alternative with a familiar API

- Repository: https://github.com/cristianbote/goober
- Website: https://goober.rocks
- Stars: 3,274 · Forks: 128
- Language: JavaScript
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/cristianbote-goober

## What goober Is and the Problem It Solves

goober is a CSS-in-JS library published on npm under the name `goober`. The core premise is that styled-components and emotion, the two most commonly used CSS-in-JS libraries, carry significant bundle weight: styled-components at 12.6 KB and emotion at 7.4 KB, according to the comparison table in the goober README. For developers building performance-sensitive applications, especially those targeting users on slower networks or lower-end devices, that overhead matters.

goober's base bundle is 1.25 KB. It achieves this by implementing the `styled` template-literal API, the `css` function for className generation, global styles via `createGlobalStyles`, SSR support via `extractCss`, theming, and keyframes, while omitting features that add bytes: debug labels, the `.attrs` chaining API, `.withComponent`, and the ClassNames utility.

The library targets any developer building with a vDOM framework who wants the CSS-in-JS authoring model without the bundle cost of the established alternatives. It works with React, Preact, Fre, and any other library that accepts a pragma function.

## The Setup Call: How goober Connects to Your vDOM Library

Unlike styled-components, which binds to React automatically, goober is framework-agnostic. The connection to a specific vDOM library happens through a required `setup()` call that passes the pragma function.

For Preact:

```jsx
import { h } from 'preact';
import { styled, setup } from 'goober';

// Should be called here, and just once
setup(h);
```

For React, you pass `React.createElement` (or the equivalent in your setup). The `setup` call must happen once before any `styled` call is made. After it runs, you use `styled` and `css` exactly as you would in styled-components:

```jsx
const Icon = styled('span')`
    display: flex;
    flex: 1;
    color: red;
`;

const Button = styled('button')`
    background: dodgerblue;
    color: white;
    border: ${Math.random()}px solid white;

    &:focus,
    &:hover {
        padding: 1em;
    }

    ${Icon} {
        color: black;
    }
`;
```

The full `setup` signature accepts four parameters: `pragma`, `prefixer`, `theme`, and `forwardProps`. The `prefixer` option connects the optional autoprefixer sub-package from `goober/prefixer`. The `theme` option wires up a theme function. The `forwardProps` option globally controls which props are forwarded to the DOM element.

## SSR, Targets, and Web Components

goober provides two features for advanced rendering contexts that the README presents as differentiating.

For server-side rendering, `extractCss(target)` collects all generated CSS for a given render and returns the critical CSS string. This is the standard SSR approach for CSS-in-JS: render to a string, extract CSS, inject it into the HTML head. The README points to a CodeSandbox example demonstrating SSR with Preact.

The `targets` feature lets goober render styles to any DOM node rather than the default document head. The README describes this as unique to goober relative to styled-components and emotion. The practical use case is web components with shadow DOM: because shadow DOM creates an isolated style scope, styles injected into the document head do not apply. By passing a target (a style element inside the shadow root), you can scope CSS to a web component's shadow tree.

This is a real architectural advantage for any project building reusable custom elements. Neither styled-components nor emotion supports rendering to an arbitrary target, according to the comparison table in the README.

## What goober Does Not Have

The README includes a comparison table that is honest about the gaps. These are API-level missing features rather than edge cases.

goober does not support `.withComponent`. In styled-components and emotion, `.withComponent` creates a new component that uses the same styles but renders a different HTML element. There is no equivalent in goober.

goober does not support `.attrs`. In styled-components, `.attrs` is used to attach default props or HTML attributes to a component. Chains like `styled.input.attrs({ type: 'text' })` are not available.

goober does not have styled.<tag> dot-notation out of the box. Writing `styled.div` instead of `styled('div')` requires `babel-plugin-transform-goober`. Without the plugin, you use the function call form.

goober does not have debug labels. emotion's Labels feature attaches a human-readable class name suffix in development, making elements identifiable in browser DevTools. goober generates class names without labels, which makes component tracing harder during development.

goober does not have ClassNames, which emotion provides for generating class strings from objects or template literals outside of the styled API.

The version 2.1.19 release was on 2026-05-13. Previous releases (2.1.18 and 2.1.17) were in October 2025.

## Autoprefixer, shouldForwardProp, and TypeScript

goober ships optional sub-packages for features that add bytes only when needed.

The autoprefixer is in `goober/prefixer`. It is passed to `setup` as the second argument:


After this, all styles generated by goober go through the prefixer before injection. The README does not specify the autoprefixing library used under the hood.

The `goober/should-forward-prop` sub-package provides a `shouldForwardProp` utility. When passed to `setup` as the `forwardProps` option, it controls which props are forwarded to the underlying DOM element versus consumed by the styled component. This mirrors the same feature in styled-components and emotion.

TypeScript support is included via `goober.d.ts` at the package root, covering the `styled`, `css`, `setup`, `extractCss`, `createGlobalStyles`, and `keyframes` APIs.

Content Security Policy is listed as a supported feature, but the README does not document the specific mechanism in the README.

The package exports follow the modern JavaScript conventions: `dist/goober.modern.js` for ESM, `dist/goober.cjs` for CommonJS, and `dist/goober.umd.js` for browser script tags. Sub-packages (`global`, `prefixer`, `should-forward-prop`) each have their own dist directories and export maps.

## When to Choose goober Over Emotion or styled-components

The decision comes down to bundle size constraints and API requirements.

Choose goober when: your application's JavaScript payload is a hard constraint (mobile-first products, low-bandwidth markets), your team does not rely on `.attrs` or `.withComponent`, you are building web components that need shadow DOM style scoping, or you want framework-agnostic CSS-in-JS that works identically in React and Preact projects.

Choose emotion when: you need debug labels for component tracing in DevTools, you use the ClassNames API, or your team is already invested in emotion's ecosystem of tooling. Emotion's base `@emotion/css` package is framework-agnostic like goober, but at approximately 7.4 KB it carries more overhead.

Choose styled-components when: you need the full API including `.withComponent`, `.attrs`, and a default export, and you are building exclusively for React. At 12.6 KB it is the heaviest of the three, but its API surface is the most complete according to the goober README's comparison table.

The `goober` package is available on npm. The MIT license permits use in commercial products without restrictions.

## Conclusion

goober makes sense for projects where JavaScript bundle size is a real constraint, or for teams building web components that need scoped CSS in arbitrary DOM targets. The styled API and SSR support cover most day-to-day CSS-in-JS needs. Where goober falls short is in the absence of debug labels (which emotion provides), the .attrs chaining API (which styled-components provides), and the styled.div dot-notation shorthand without a Babel plugin. Teams that rely on those features in their current setup will find goober's missing API surface a friction point. For projects that can tolerate those trade-offs, the version 2.1.19 release on 2026-05-13 shows the library is maintained.

## FAQ

### How do you use goober with React or Preact?

Call `setup(pragma)` once at the top of your application before any styled calls, passing your framework's createElement function (React.createElement for React, h for Preact). After that, import and use styled and css exactly as you would in styled-components.

### Does goober support server-side rendering?

Yes. Use `extractCss(target)` to collect the critical CSS after a server-side render. Inject the returned string into a style tag in your HTML head. The README points to a CodeSandbox example demonstrating SSR with Preact.

### What is the difference between goober and styled-components?

goober's base bundle is 1.25 KB versus styled-components at 12.6 KB. goober supports the styled template-literal API, SSR, theming, global styles, and keyframes. It does not support .attrs, .withComponent, debug labels, or the ClassNames API. goober also works with Preact and other vDOM libraries, while styled-components targets React only.

## Sources

- [cristianbote/goober on GitHub](https://github.com/cristianbote/goober)
- [License: MIT](https://github.com/cristianbote/goober/blob/master/LICENSE)
- [Project website](https://goober.rocks)
- [README](https://github.com/cristianbote/goober/blob/master/README.md)
- [Releases](https://github.com/cristianbote/goober/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cristianbote-goober
