css_module

Attribute Macro css_module 

Source
#[css_module]
Available on crate feature prelude only.
Expand description

Generate type-safe styles with scoped CSS class names.

The css_module attribute macro creates scoped CSS modules that prevent class name collisions by making each class globally unique. It expands the annotated struct to provide type-safe identifiers for your CSS classes, allowing you to reference styles in your Rust code with compile-time guarantees.

§Syntax

The css_module attribute takes:

  • The asset string path - the absolute path (from the crate root) to your CSS file.
  • Optional AssetOptions to configure the processing of your CSS module.

It must be applied to a unit struct:

#[css_module("/assets/my-styles.css")]
struct Styles;

#[css_module("/assets/my-styles.css", AssetOptions::css_module().with_minify(true))]
struct Styles;

§Generation

The css_module attribute macro does two things:

  • It generates an asset and automatically inserts it as a stylesheet link in the document.
  • It expands the annotated struct with snake-case associated constants for your CSS class names.
// This macro usage:
#[css_module("/assets/mycss.css")]
struct Styles;

// Will expand the struct to (simplified):
struct Styles {}

impl Styles {
    // Snake-cased class names can be accessed like this:
    pub const your_class: &str = "your_class-a1b2c3";
}

§CSS Class Name Scoping

The macro only processes CSS class selectors (.class-name). Other selectors like IDs (#id), element selectors (div, p), attribute selectors, etc. are left unchanged and not exposed as Rust constants.

The macro collects all class selectors in your CSS file and transforms them to be globally unique by appending a hash. For example, .myClass becomes .myClass-a1b2c3 where a1b2c3 is a hash of the file path.

Class names are converted to snake_case for the Rust constants. For example:

  • .fooBar becomes Styles::foo_bar
  • .my-class becomes Styles::my_class

To prevent a class from being scoped, wrap it in :global():

/* This class will be scoped */
.my-class { color: blue; }

/* This class will NOT be scoped (no hash added) */
:global(.global-class) { color: red; }

/* Element selectors and other CSS remain unchanged */
div { margin: 0; }
#my-id { padding: 10px; }

§Using Multiple CSS Modules

Multiple css_module attributes can be used in the same scope by applying them to different structs:

// First CSS module
#[css_module("/assets/styles1.css")]
struct Styles;

// Second CSS module with a different struct name
#[css_module("/assets/styles2.css")]
struct OtherStyles;

// Access classes from both:
rsx! {
    div { class: Styles::container }
    div { class: OtherStyles::button }
}

§Asset Options

Similar to the asset!() macro, you can pass optional AssetOptions to configure processing:

#[css_module(
    "/assets/mycss.css",
    AssetOptions::css_module()
        .with_minify(true)
        .with_preload(false)
)]
struct Styles;

§Example

First create a CSS file:

/* assets/styles.css */

.container {
    padding: 20px;
}

.button {
    background-color: #373737;
}

:global(.global-text) {
    font-weight: bold;
}

Then use the css_module attribute:

use dioxus::prelude::*;

fn app() -> Element {
    #[css_module("/assets/styles.css")]
    struct Styles;
     
    rsx! {
        div { class: Styles::container,
            button { class: Styles::button, "Click me" }
            span { class: Styles::global_text, "This uses global class" }
        }
    }
}