I Created a Zero-Runtime CSS-in-JS Library Compatible with Next.js App Router and RSC

Introducing Kuma UI: A Utility-First, Performance-Optimized CSS-in-JS Library Compatible with Modern React Frameworks

poteboy
Bits and Pieces

--

Kuma UI: 🐻 zero-runtime CSS-in-JS with type-safe utility props

Have you ever wished for a way to style your React components like Chakra UI but without any runtime overhead? I did. And so, I set out to build just that.

Over my years of working with React, I’ve loved using CSS-in-JS libraries like Emotion and Styled-components. However, their inherent performance overhead from injecting CSS at runtime and their incompatibility with the latest Next.js features such as App Router and React Server Components (RSC) have always been a nagging issue for me.

That’s why I built Kuma UI: zero-runtime CSS-in-JS Library with type-safe utility props. By the way, ‘Kuma’ means ‘bear’ in Japanese — I named it that way simply because bears are so cute, aren’t they? 🐻

💡 Pro Tip: With Bit, you can create, test, visualize, and independently version and publish components built using any CSS-in-JS library. You can also create a streamlined workflow for building more of them, with Bit’s custom envs for each ‘type’ of reusable component that you might want to build.

Learn more here:

The Performance Problem with Runtime CSS-in-JS

Before diving deep into what Kuma UI is and how it works, let’s first take a moment to understand why runtime CSS-in-JS can be problematic for performance. This will give us a better understanding of the issues that Kuma UI is designed to solve.

Despite its popularity in modern frontend development, CSS-in-JS comes with certain performance costs tied to the generation of CSS during JavaScript runtime. Additionally, since it involves manipulating the DOM at runtime, it is not compatible with App Router and RSC, which generate components on the server-side.

Here are the two primary performance concerns:

  1. Parsing JavaScript CSS Objects: CSS-in-JS libraries need to parse JavaScript CSS objects into actual CSS. This parsing (or serialization) process can be computationally expensive, particularly for large applications with complex styles.
  2. Injecting Styles into the DOM: Once the CSS has been parsed, it must then be injected into the DOM. This can cause a significant increase in the workload of the browser’s layout engine, potentially leading to janky animations and slow rendering times.

Some libraries, such as Stitches, claim near-zero runtime performance overhead by tackling the first issue (parsing JavaScript CSS objects). Nevertheless, they still inject the parsed CSS into the DOM at runtime, which means they haven’t entirely eliminated the performance concerns.

That’s where Kuma UI comes in. It aims to address both of these performance issues by offering a zero-runtime CSS-in-JS solution with a syntax that resembles popular libraries like Chakra UI and Styled System. Let’s take a closer look at Kuma UI and see how it achieves this.

Introducing Kuma UI: Zero-Runtime CSS-in-JS with Utility Props

Kuma UI is designed to deliver top-notch performance by eliminating both parsing and injecting of CSS during runtime. It does this by generating CSS ahead-of-time during the build process, ensuring that no runtime overhead is incurred.

Kuma UI offers two primary APIs: styled and k. The styled function allows you to create reusable styled components with predefined styles, while the k API provides you with pre-styled HTML elements for quick component building. Both these APIs support utility props for inline styling. These utility props are type-safe and work similarly to those in Chakra UI, allowing you to write responsive styles with ease.

Here’s an example of how you might use Kuma UI in a React application:

import { styled, k } from "@kuma-ui/core";

const color = 'orange'
function App() {
return (
<VStack p={[4, 8]} m="2px" _hover={{ flexDir: "row" }}>
<k.div fontSize="40px" color={color}>
hello world
</k.div>
</VStack>
);
}

export const VStack = styled("div")`
display: flex;
flex-direction: column;
`;

export default App;

In this example, we’ve used both the styled function to create a reusable VStack component and the k API for inline styles. The utility props support string, number, or array values for responsive design based on predefined breakpoints which users can freely customize.

Since Kuma UI extracts all styles during the build process and emits external CSS files, the resulting gzipped bundle size of @kuma-ui/core is just 182 bytes. That’s incredibly lightweight compared to other CSS-in-JS libraries!

And remember, Kuma UI is experimentally compatible with Next.js App Router and RSC, allowing you to take full advantage of these powerful new technologies.

Kuma UI Under the Hood: How It Works

To start using Kuma UI, you need to set up your next.config.js as follows:

const { withKumaUI } = require("@kuma-ui/next-plugin");

/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};

module.exports = withKumaUI(nextConfig);

This setup allows Kuma UI to intervene in the Webpack build process. During this process, the Babel transpiler converts source code into an Abstract Syntax Tree (AST). Babel has a powerful plugin system, which makes it not just a downlevel compiler (a tool that replaces new syntax with old syntax) but also a widely used metaprogramming tool.

https://www.sitepoint.com/understanding-asts-building-babel-plugin/

In case you’re not familiar, an Abstract Syntax Tree (AST) is a tree representation of the abstract syntactic structure of source code written in a programming language. Each node of the tree denotes a construct occurring in the source code. Babel, as a JavaScript compiler, uses ASTs to parse and generate JavaScript code. This transformation to an AST allows Kuma UI to manipulate the code effectively during the build process.

Kuma UI goes through this AST and extracts style props like fontSize from elements like <k.div fontSize={24} />. It then generates CSS based on these values. The generated CSS is outputted to a virtual file using a Webpack plugin. This allows CSS classes to be applied without computing in JavaScript at runtime.

Regarding the experimental support for Next.js App Router, Kuma UI handles it through a similar process. According to the official Next.js documentation, they’re currently working with the React team to develop upstream APIs to handle CSS and JavaScript assets with support for React Server Components and streaming architecture. As of now, there are no APIs available for library developers, and virtual file outputs are not supported. Despite this, Kuma UI provides experimental support by writing the generated CSS to a temporary directory and importing them in the code.

Wrapping Up and Looking Ahead

Kuma UI is just at the beginning of its journey, with only a month into development. But we’re aiming high — planning to introduce features like theming and headless components, turning Kuma UI into a go-to tool for constructing design systems.

I want to be fully transparent and let you know that using Kuma UI in a production environment is, at this stage, premature. However, we’re working hard to get to a major release that provides a robust, high-performance solution to CSS-in-JS.

We’re a small team, and every contribution, however small, is valuable to us. So, if you’re interested in making Kuma UI even better, we welcome your contributions.

If you find Kuma UI intriguing or helpful, we’d appreciate it if you could give us a star ⭐️ on GitHub. Every bit of support fuels our passion for pushing the boundaries of frontend development.

Build Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--