After years of dealing with the frustrations of traditional styling methods, I’m excited to announce the beta launch of Clanga: a JavaScript-to-CSS compiler that rethinks how we write styles.
Forget everything you know about CSS-in-JS — Clanga is not a CSS-in-JS library.
Instead, it lets you define pure CSS styles using JavaScript — no runtime overhead, no client-side hacks.
npm install clanga
in vite.config.js write this:
import { defineConfig } from 'vite'
import clanga from 'clanga/plugins/clanga-vite.js'
// https://vite.dev/config/
export default defineConfig({
plugins: [ ... , clanga() ],
})
write your .style.js file as such (let's call thisexample.style.js):
import { Style, Flex, This, hsl } from "clanga";
// Define theme colors
const primary = hsl(163, 54, 25);
const background = hsl(163, 54, 95);
const text = hsl(160, 52, 9);
// Apply styles
Style(".my-div", {
all: Div()
.align({ wstretch: true, left: "20px", right: "20px" })
.shape({ h: "200px" }) .color({ fg: text, bg: background }),
xs: Div().visual({ h: "70%" }),
xl: Div().visual({ h: "768px" }),
});
then run (if not using vite plugin)
npx clanga
when this code runs you will see compiled .style.css file to be used (in this case it will be example.style.css)
import { Sheet, Flex, Div } from "clanga";
// will not be included in the CSS unless you call .apply on this
const listStyle = Sheet({
xs: Flex()
.use({ gap: "2px", mode: "row" })
.align({ xcenter: true, ycenter: true })
.shape({ w: "100%", h: "50px" }),
xl: Flex()
.use({ gap: "2px", mode: "row" })
.align({ xcenter: true, ycenter: true })
.shape({ w: "300px", h: "50px" }),
});
// Clone and extend the base style
const improved_list = listStyle.clone();
// extend styles to add more of them
improved_list.extend({
all: Div().color({ fg: "#1e1e1e" }).pad({ left: "20px", right: "20px" }),
});
// Apply styles to an actual selector
// in this case it creates a class in the compiled css file for this
improved_list.apply(".MyButton");
all : all screens,xxxxs : 90px and wider screensxxxs : 156px and wider screensxxs : 270px and wider screensxs : 319px and wider screenss : 568px and wider screensm : 768px and wider screensl : 1024px and wider screensxl : 1280px and wider screensxxl : 1920px and wider screensxxxl : 2560px and wider screensxxxxl : 3840px and wider screensxxxxxl : 6016px and wider screensmain functions are Div , Flex and Sheets
Div()Div().align({ ... }).shape({ ... }).color({ ... }).font({ ... }).pad({ ... }).extra({ ... });
.font({ ... })family: same as font-family in CSSline_height: same as line-height in CSSweight: same as font-weight in CSSsize: same as font-size in CSSvariant_caps: same as font-variant-caps in CSSstretch: same as font-stretch in CSSword_spacing: same as word-spacing in CSSletter_spacing: same as letter-spacing in CSSvariant: same as font-variant in CSSindent: same as text-indent in CSSword_break: same as line-height in CSShyphens: same as line-height in CSSoverflow: same as line-height in CSSbreak_word: if true will set overflow-wrap to breakalign: same as text-align in CSSalign_last: same as text-align-last in CSStransform: same as text-transform in CSSdecoration: same as text-decoration in CSSdecoration_color: same as text-decoration-color in CSSdecoration_style: same as text-decoration-style in CSSdirection: same as direction in CSSwriting_mode: same as writing-mode in CSSwhite_space: same as white-space in CSSthis — The instance itself, enabling method chaining.Div().font({
family: "Arial, sans-serif",
size: "16px",
weight: "bold",
line_height: 1.5,
align: "center",
decoration: "underline",
break_word: true
});
.align({ ... }) optionstop, bottom, left, right: string (px, %, etc.)z: z-indexfixed, relative, sticky: booleans for positionxcenter, ycenter: booleans for centeringwstretch, hstretch: booleans for stretching.shape({ ... }) optionsradius: border radius stylesw, h: width and height (not allowed if wstretch/hstretch is used).border({ ... }) let's you selectalltopbottomrightleftEach of these sides can have { color , width , style }, each of these properties are strings for styles
corresponding to border-color,border-width and border-style.
.pad({ ... }) optionsall : padding for all sidesright: right paddingleft: left paddingtop: top paddingbottom: bottom padding.color({ ... }) optionsfg: colorbg: background color.extra({ styles })Set arbitrary CSS styles using a dictionary.
Sheet( initialStyles ) returns an object containing.apply(selector): apply sheet to an actual CSS selector.modify(styles): modify styles in the sheet.clone(): returns a clone of the original sheet with same styles to be extended furtherFlex()Flex().use({ mode: "row", gap: "10px", wrap: true })
.justify({ row: "center", col: "space-evenly" });
.use({ ... })main flex box options
mode: "row" or "col"gap: CSS gapwrap: booleanreverse: reverse direction (boolean)reverse_wrap: reverse wrapping direction (boolean).justify({ row, col })Aligns content depending on mode
row: "start" or "center" or "end" or "space-between" or "space-around" or "space-evenly"col: "start" or "center" or "end" or "space-between" or "space-around" or "space-evenly".itemClass(selector, { grow, shrink, basis })Defines flex item styles for children with a class.
.item(nthChild, { grow, shrink, basis })Same as above but for a specific :nth-child(...)
Helper functions:
hsl(h, s, l, a?) // returns `hsl(...)`
rgb(r, g, b, a?) // returns `rgba(...)`
// a is optional for opacity
Style(".my-class_name", {
all: ...Clanga/Flex instance...,
xs: ...,
s: ...,
m: ...,
l: ...,
xl: ...
});
compiler.js (not shown here).wstretch can’t be used with w, also hstretch can’t be used with hDiv() and Flex() to construct components..child(n, style) or .substyle(name, style) for nested elements.xs, s, m, l, xl
import { hsl , Style , Flex , Div } from "clanga";
// themes (optional but very useful)
const
primary = hsl( 163, 54, 25 ),
secondary = hsl( 216, 55, 68 ),
accent = hsl( 239, 55, 41 ),
background = hsl( 163, 54, 95 ),
text = hsl( 160, 52, 9 )
;
Style(".my-list", {
all: Flex().use({ mode: "row", wrap: true, gap: "20px" })
.visual({ h: "200px", fg: text, bg: background })
.itemClass("my-child", { grow: 1 }),
s: Div().visual({ w: "70%" }),
});
Contributions are welcome! Please fork the repository and submit a pull request.
This project is licensed under the MIT License. See the LICENSE for details.