A type-safe CSS-in-JS library for Deno with scoped styles, theming, and a complete CSS AST.
This project was vibe coded with Claude.
@baetheus/css provides a complete CSS Abstract Syntax Tree and a high-level
API for creating scoped styles, CSS variables, keyframe animations, font faces,
layers, and recipes (variant-based component styles). All styles are compiled to
CSS AST rules that can be rendered to strings.
- Scoped class name generation with content-based hashing
- Full CSS AST representation for all major at-rules (@media, @supports, @container, @keyframes, @font-face, @layer, @property)
- CSS variable theming with type-safe contracts
- Recipe pattern for variant-based component styles
- Style composition and merging
- Selector builders (class, id, tag, attribute, pseudo-class, pseudo-element, combinators)
- Zero runtime in production (all CSS is generated at build time)
deno add jsr:@baetheus/cssimport { render, style } from "@baetheus/css/core";
const button = style({
backgroundColor: "blue",
color: "white",
padding: "8px 16px",
borderRadius: 4,
selectors: {
"&:hover": { backgroundColor: "darkblue" },
},
});
// Use in DOM
element.className = button.toString();
// Render CSS
const css = render([button]);import { createVars, render, style, vars } from "@baetheus/css/core";
const theme = createVars({
colors: {
primary: null,
secondary: null,
},
});
const lightTheme = vars(theme, {
colors: { primary: "#0066cc", secondary: "#666666" },
});
const darkTheme = vars(theme, {
colors: { primary: "#66b3ff", secondary: "#cccccc" },
});
const card = style({
backgroundColor: theme.colors.primary,
color: theme.colors.secondary,
});
// Apply theme
document.body.className = lightTheme.toString();import { recipe, render } from "@baetheus/css/core";
const button = recipe({
base: {
display: "inline-flex",
alignItems: "center",
borderRadius: 4,
},
variants: {
size: {
small: { padding: "4px 8px", fontSize: 12 },
large: { padding: "12px 24px", fontSize: 16 },
},
variant: {
primary: { backgroundColor: "blue", color: "white" },
ghost: { backgroundColor: "transparent", color: "blue" },
},
},
defaultVariants: {
size: "small",
variant: "primary",
},
});
// Use with defaults
element.className = button.toString();
// Use with specific variants
element.className = button.with({ size: "large", variant: "ghost" });import { keyframes, render, style } from "@baetheus/css/core";
const fadeIn = keyframes({
from: { opacity: 0 },
to: { opacity: 1 },
});
const animated = style({
animation: `${fadeIn} 0.3s ease-out`,
});import { cls, mediaRule, prop, renderRule, styleRule } from "@baetheus/css/ast";
const rule = styleRule(cls("button"), [
prop("display", "inline-flex"),
prop("padding", "8px 16px"),
]);
const responsive = mediaRule("(min-width: 768px)", [
styleRule(cls("container"), [prop("width", "750px")]),
]);
console.log(renderRule(rule));
console.log(renderRule(responsive));- vanilla-extract - The primary inspiration
for the API design, particularly the
style,recipe,createVar, and theming patterns - Sass - Influence on nesting and selector composition
- fp-ts - Functional programming patterns and type-safe design
Contributions are welcome! This is an experimental project that was vibe coded, so there's plenty of room for improvement.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Run tests
deno test
# Type check
deno check ast.ts core.ts
# Format
deno fmtMIT License - see LICENSE for details.