INTRODUCTION
Introduction
What Plumeria is, what writing styles with it looks like, and how far its types reach.
Plumeria is a compile-time CSS-in-JS library for React. You write style objects in TypeScript, and the compiler turns them into static atomic CSS — while removing every trace of the library from your JavaScript bundle. No runtime code ships, no styles are computed in the browser.
Because styles are compiled instead of injected, the order of the generated CSS is decided by the compiler's module graph, not by the order a bundler happens to emit chunks — split and rearrange files, and the layout holds.
Usage
Styling is straightforward: define styles once with css.create(), and the compiler handles everything else. The atomic class names are determined at that point — all that remains is to attach them via the classStyle prop.
import * as css from "@plumeria/core";
const styles = css.create({
text: {
fontSize: 16,
},
});
export const Footer = () => {
return <div classStyle={styles.text}>MyText</div>;
};Styles compile to zero across file boundaries, too. You can colocate styles with components or share them across files — structure them to fit your project. A file that applies them with classStyle needs nothing else. A file that passes them to a component through any other prop imports @plumeria/core, which is how the compiler finds it; importing it in every file that uses Plumeria is always safe and keeps each file on the fastest path.
import * as css from "@plumeria/core";
export const styles = css.create({
common: {
color: "gray",
},
});import { styles } from "./styles";
export const Component = () => {
return <p classStyle={styles.common}>Shared style</p>;
};Specificity
The classStyle prop accepts arrays, ternaries, and conditional expressions. Merging follows one rule: the right side wins. If isActive is true, the properties of active override the properties of base — always.
const styles = css.create({
base: {
color: "gray",
fontSize: 16,
},
active: {
color: "blue",
},
});
classStyle={[styles.base, isActive && styles.active]}Because the compiler controls the merge, it settles specificity instead of the cascade, apart from the few pairs listed in Specificity. Writing the merge as an operation, where combines styles left to right, disjoint styles simply concatenate:
And when two styles set the same property, the losing atom on the left is filtered out at compile time — it never reaches the output:
A shorthand against a longhand is the exception: the longhand wins wherever the two meet, in either order. The laws this merge obeys are in Composition laws.
Types all the way down
Styling shouldn't require a runtime. Plumeria treats styles as type schemas rather than runtime objects — in fact, the package's only entry point is a .d.ts file. There is no JavaScript to import:
{
"name": "@plumeria/core",
"exports": {
".": {
"types": "./lib/css.d.ts",
},
},
}Static styles resolve to class names entirely at compile time. The only dynamic pieces — function keys and variant props — compile down to CSS variables, so even they leave no JavaScript behind. Every API compiles to nothing but static class names and CSS:
- No runtime bundle
- No runtime evaluation
- No runtime parsing
- No runtime dependencies
Of course, "zero-runtime" doesn't claim the cost vanishes — it claims the cost moves. All of the work happens at build time, and the browser only ever receives class names and CSS.
To learn what motivated this design, read Why Plumeria?. For integration with bundlers and the full API, see the API reference and Installation.
This site is built with Plumeria. The documentation app lives in the same repository and depends on the workspace packages, so every release is exercised here — and every experiment is tried here — before it ships.