🥜 goober, a less than 1KB css-in-js solution.
I always wondered, if you can get a working solution for css-in-js with a smaller footprint. I started a project and wanted a to use styled-components. Looking at their sizes, it seems that I would rather not include ~16kB(styled-components) or ~11kB(emotion) just so I can use the styled
paradigm. So, I embarked in a mission to create a smaller alternative for these well established apis.
The API is inspired by emotion, styled
function. Meaning, you call it with your tagName
and returns a vDOM component for that tag. Note, setPragma
is needed to be run before the styled
function is used.
import { h } from "preact";
import { styled, setPragma } from "goober";
// Should be called here, and just once
setPragma(h);
const Icon = styled("i")`
display: flex;
flex: 1;
color: red;
`;
const Button = styled("button")`
background: dodgerblue;
color: white;
border: ${Math.random()}px solid white;
&:focus,
&:hover {
padding: 1em;
}
.otherClass {
margin: 0;
}
${Icon} {
color: black;
}
`;
You can get the critical CSS for SSR, via extractCss
. Take a look at this example: CodeSandbox: SSR with Preact and goober
As you can see it supports most of the syntaxes of CSS. If you find any issues, please submit a ticket or even a PR with a fix.
@param {String} tagName
The name of the dom element you'd like the styled to be applied to@returns {Function}
Returns the tag template function.
import { styled } from "goober";
const Btn = styled("button")`
border-radius: 4px;
`;
Given the fact that react
uses createElement
for the transformed elements and preact
uses h
, setPragma
should be called with the proper pragma function. This was added to reduce the bundled size and being able to bundle esmodule version. At the moment I think it's the best tradeoff we can have.
import React from "react";
import { setPragma } from "goober";
setPragma(React.createElement);
@returns {Function}
Returns the tag template function.
Same as styled
but without the tagName and vNode generation. In the end the output will be a className.
import { css } from "goober";
const BtnClassName = css`
border-radius: 4px;
`();
// (!) Note the empty param at the end. If you wanna use `props` throughout the syntax this is the place to put them
const btn = document.querySelector("#btn");
btn.classList.add(BtnClassName);
@returns {String}
Returns the <style>
tag should be rendered in your document <head>
and clears the cache.
const { extractCss } = require("goober");
// After your app has rendered, just call it:
const styleTag = extractCss();
To create a global style, you need to call styled
with the global
string and your tagged template.
import { styled } from "goober";
styled("global")`
html,
body {
background: light;
}
* {
box-sizing: border-box;
}
`;
- Basic CSS parsing
- Nested rules with pseudo selectors
- Nested styled components
- Media queries (@media)
- Keyframes (@keyframes)
- Smart(lazy) client-side hydration
- Vanilla(via
css
function) -
globalStyle
so one would be able to create global styles - Vendor prefixing
Feel free to try it out and checkout the examples. If you wanna fix something feel free to open a issue or a PR.