#css-class #css #dioxus #wasm-binary #wasm #gui #jss

css-in-rs

Library to manage component-level CSS in Rust

6 releases

0.2.0 Jan 23, 2024
0.1.4 Jan 19, 2024

#1830 in Web programming

MIT license

25KB
259 lines

css-in-rs

A library for embedding dynamic CSS in Rust (wasm); inspired by cssinjs/jss

This crate is designed to be framework-independent. It currently provides integrations for Dioxus, which is disabled by default.

Use case

This crate allows to develop reusable components for the web which bundle their own styles. Thanks to dead-code-analysis in Rust, only the styles which are actually used will be included in the final wasm binary.

Features:

  • A procmacro make_styles! to write css directly in Rust
  • A runtime to inject the styles on a as-need basis. If styles are not used, they won't be included in the final binary
  • Styles will only be mounted once, even if requested multiple times
  • Dynamically created classnames to avoid collisions. You can choose common names like active for multiple components without problems
  • Compile time checks: Rust will warn you if classnames defined in your styles are never used. If they don't exist, you'll get an error

Basic idea

You embed your CSS code with classnames of your choice using the make_styles! procmacro. It will generate a new rust struct for the final runtime-names of the used css classes. For each css class in your style, a classname: String member will be available in the struct. See the documentation for make_styles! for more details.

Styles generated this way can be mounted. On the first mount, classnames are generated at runtime to avoid collisions and returned in the struct created by the procmacro. You can therefore access the created classnames using the struct. Since the struct's type is generated at compile time, the compiler will complain if you use undefined css classes and warn you about unused classes.

Styles are only mounted once. You can try to do it repeatedly, but it will be a no-op. You'll get a reference to the classnames-struct which was created the first time. Therefore, you can reuse your created styles in many components, and you do no not need to worry about mounting them too many times.

Example (Dioxus):

#![allow(non_snake_case)]

use css_in_rs::{Classes, EmptyTheme, make_styles, use_style_provider_quickstart};
use dioxus::prelude::*;

// Will create a new struct `MyClasses` with three members:
//  `red_text`, `primary` and `disabled`
make_styles! {
    (_theme: EmptyTheme) -> MyClasses {
        red_text {          // defines a new css class: `red_text`
            color: "red",
            margin: "5px",
        },
        "button" {          // does not define any new css classes
            margin: "5px",
            padding: "5px",
            width: "10em",
        },
        "button.primary" {  // defines a new css class: `primary`
            border: "2px solid red",
        },
        "button.disabled" { // Shows a rust warning: "field never read"
            disabled: true,
        },
    }
}

fn Demo(cx: Scope) -> Element {
    let classes: &MyClasses = MyClasses::use_style(cx);

    render! {
        div {
            class: &classes.red_text as &str,
            "This text is supposed to be red.",
        }
        button {
            class: &classes.primary as &str,
            "Click me",
        }
    }
}

fn App(cx: Scope) -> Element {
    use_style_provider_quickstart(cx, || EmptyTheme);

    cx.render(rsx! {
        Demo {}
    })
}

fn main() {
    // launch the web app
    dioxus_web::launch(App);
}

Dependencies

~8–10MB
~200K SLoC