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 break
align
: 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({ ... })
options:top
, bottom
, left
, right
: string (px, %, etc.)z
: z-indexfixed
, relative
, sticky
: booleans for positionxcenter
, ycenter
: booleans for centeringwstretch
, hstretch
: booleans for stretching.shape({ ... })
options:border
: border stylesradius
: border radius stylesw
, h
: width and height (not allowed if wstretch
/hstretch
is used).pad({ ... })
options:all
: padding for all sidesright
: right paddingleft
: left paddingtop
: top paddingbottom
: bottom padding.color({ ... })
options:fg
: 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 h
Div()
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.