60. Framework Docs
Blend CSS-in-JS
Blend is Braid's CSS-in-JS framework (braid-lang/lib/frameworks/blend/blend.br, 618 lines). It generates atomic class names, supports theming (light/dark), responsive breakpoints, @keyframes/@font-face/@import, critical CSS extraction, minification, vendor prefixing, Z-index management, and spacing/typography scales.
Core API
Style Definition
// Define a scoped style — generates an atomic class name
fn style(properties: object) -> BlendStyle
// Define a global style (selector-based, no class name)
fn global_style(selector: string, properties: object) -> BlendStylelet card_style = blend.style({
backgroundColor: "#fff",
borderRadius: "8px",
padding: "16px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)"
});
// Access the generated class
let class_name = blend.blend_class(card_style);
// Returns something like "blend-847291"Unit & Color Helpers
fn px(val: int) -> string // "42px"
fn rem(val: int) -> string // "2rem"
fn em(val: int) -> string
fn percent(val: int) -> string
fn vh(val: int) -> string
fn vw(val: int) -> string
fn hex(val: string) -> string // "#ff0000"
fn rgb(r, g, b) -> string // "rgb(255,0,0)"
fn rgba(r, g, b, a) -> string // "rgba(255,0,0,0.5)"Stylesheet Generation
// Generate complete stylesheet CSS from one or more style objects
fn generate_stylesheet(styles: object) -> string
// Render a single style object to CSS
fn render_style(style_obj: object) -> string
// Inject stylesheet as a <style> element (returns a Bond VDOM node)
fn inject_stylesheet(css_string: string, id: string) -> objectTheme System
// Define design tokens
let tokens = blend.create_theme({
primary: "#1a73e8",
background: "#ffffff",
text: "#1f1f1f",
border: "#dadce0",
surface: "#f8f9fa"
});
// Access a token as a CSS variable
let primary_var = blend.var("primary");
// Returns "var(--primary)"Light/Dark Theme Config
let theme = blend.create_theme_config(
{ background: "#fff", text: "#000", primary: "#1a73e8" },
{ background: "#121212", text: "#eee", primary: "#bb86fc" }
);
theme.set_theme("dark");
let tokens = theme.get_tokens();
let css_vars = theme.generate_theme_variables();
// Outputs: :root { --background: #121212; --text: #eee; ... }
// Dark mode style — emits @media (prefers-color-scheme: dark)
let btn = blend.dark_mode_style(
{ background: "#fff", color: "#000" },
{ background: "#333", color: "#fff" }
);@keyframes, @font-face, @import
// Keyframes animation
let fade_in = blend.keyframes("fadeIn", {
"0%": { opacity: "0", transform: "translateY(10px)" },
"100%": { opacity: "1", transform: "translateY(0)" }
});
// Usage in style
let animated = blend.style({
animation: blend.animation("fadeIn", "0.3s", "ease-out", "0s", "1", "normal"),
opacity: "0"
});
// Font face
let custom_font = blend.font_face({
fontFamily: "Inter",
src: "url('/fonts/Inter-Regular.woff2') format('woff2')",
fontWeight: "400",
fontStyle: "normal"
});
// External import
let external = blend.import_style("https://fonts.googleapis.com/css2?family=Inter");Pseudo-classes & Media Queries
// Pseudo-class
let hover_btn = blend.pseudo("hover", {
backgroundColor: "#1557b0",
boxShadow: "0 4px 8px rgba(0,0,0,0.2)"
});
// Media query
let responsive = blend.media("(max-width: 768px)", {
padding: "8px",
fontSize: "14px"
});
// Both can be combined:
let s = blend.style({ color: "red", fontSize: "16px" });
s.pseudo_class = "hover";
s.media_query = "(min-width: 768px)";Responsive Breakpoints
let bp = blend.create_breakpoints();
// { xs: "0px", sm: "576px", md: "768px", lg: "992px", xl: "1200px" }
let mobile_up = blend.breakpoint_up(bp.sm); // "(min-width: 576px)"
let tablet_down = blend.breakpoint_down(bp.md); // "(max-width: 768px)"
let between = blend.breakpoint_between(bp.sm, bp.lg);
// Shorthand for responsive styles
let desktop_card = blend.responsive_style(bp.lg, {
display: "flex",
gap: "24px"
});Dark Mode Auto-Switching
// Blend automatically wraps dark mode styles in:
@media (prefers-color-scheme: dark) {
.blend-xxx { background: #333; color: #fff; }
}
// Generated by render_with_dark_mode(selector, light_props, dark_props)
// Also available: theme.dark_mode_global_style(selector, properties)
// which maps theme token keys to dark valuesCritical CSS Extraction
let extractor = blend.create_critical_css_extractor();
extractor.mark_above_fold(".hero");
extractor.add_rule(hero_style);
let critical_css = extractor.extract_critical(all_styles);
let split = extractor.split_critical_async(full_css);
// split.critical — inline in <head>
// split.async — load asynchronouslyCSS Minification
let minified = blend.minify_css(raw_css_string);
// Strips comments, collapses whitespace, minimal outputVendor Prefixing
// Auto-prefixes: transform, transition, animation, appearance,
// user-select, backdrop-filter, clip-path, mask, box-decoration-break
let prefixed = blend.apply_vendor_prefixes_to_properties({
transform: "rotate(45deg)",
appearance: "none"
});
// Adds -webkit-transform, -moz-transform, etc.Z-Index Management
let z = blend.create_z_index_system();
// Predefined layers: base(0), dropdown(100), sticky(200),
// navbar(300), modal-backdrop(400), modal(500),
// popover(600), tooltip(700), toast(800), loading(900), max(9999)
let modal_layer = z.get_layer("modal"); // 500
let next_idx = z.get_next(); // 1, 2, 3...
z.set_layer("my-layer", 250);Spacing Scale
let spacing = blend.create_spacing_scale(4);
// Factors: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40, 48, 56, 64]
spacing.get(3); // "12px" (3 * 4)
spacing.margin(4); // "margin: 16px"
spacing.padding(6); // "padding: 24px"
spacing.gap(8); // "gap: 32px"Typography Scale
let type = blend.create_typography_scale(16, 1.25);
// Default ratio: 1.25 (major third)
// Levels: h1-h6, body, small, caption
type.get_size("h1"); // ~61px (16 * 1.25^5)
type.get_line_height("h1"); // 1.2
type.heading_style("h2");
// { fontSize: "49px", lineHeight: "1.25" }Theme Toggle Example
import bond;
import blend;
let theme = blend.create_theme_config(
{ bg: "#fff", text: "#333", card: "#f5f5f5" },
{ bg: "#1a1a2e", text: "#eee", card: "#16213e" }
);
fn ToggleButton() {
return bond.button(
theme.current_theme == "light" ? "Switch to Dark" : "Switch to Light",
{
onClick: fn() { theme.toggle_theme(); },
class: blend.blend_class(blend.style({
padding: "12px 24px",
cursor: "pointer",
border: "none",
borderRadius: "6px",
background: blend.var("bg"),
color: blend.var("text")
}))
}
);
}Responsive Component Example
import bond;
import blend;
let bp = blend.create_breakpoints();
let mobile_card = blend.style({
width: "100%",
padding: "12px",
fontSize: "14px"
});
let desktop_card = blend.responsive_style(bp.lg, {
width: "600px",
padding: "32px",
fontSize: "18px"
});
let combined = blend.generate_stylesheet([mobile_card, desktop_card]);
let style_element = blend.inject_stylesheet(combined, "card-styles");
fn ResponsiveCard(props) {
return bond.fragment([
style_element,
bond.div({ class: blend.blend_class(mobile_card) }, [
bond.h2(props.title, {}),
bond.p(props.body, {})
])
]);
}Internal Architecture
Blend converts camelCase property names to kebab-case via camel_to_kebab(str), generates unique class names via simple_hash(stringify_properties(properties)), and renders styles as either global selectors or atomic classes. The BlendStyle struct carries all metadata needed for media queries, pseudo-classes, dark mode, animations, font faces, and imports — enabling a single unified rendering pipeline via render_style().