dioxus_style
Scoped CSS styling for Dioxus components - Write CSS that's automatically scoped to your components, preventing style conflicts and maintaining clean, modular code.
Features
- 🎯 Automatic CSS Scoping - Classes are automatically prefixed with unique hashes
- 📦 File or Inline CSS - Load from
.cssfiles or write inline - ⚡ Zero Runtime Overhead - All processing happens at compile time
- 🔥 Hot Reload Support - CSS changes are tracked via
include_str! - 🎨 Multiple Macro Options - Choose the syntax that fits your style
- 🚀 Performance Optimized - Fast hashing (xxHash), efficient parsing, and minification in release builds
- 💾 Global Style Registry - Automatic deduplication and insertion order preservation
Quick Start
Add to your Cargo.toml:
[]
= "0.1.0"
Usage Examples
1. Attribute Macro with Auto-Injection (Recommended)
The simplest way - styles are automatically injected:
use *;
use with_css;
button.css:
}
}
2. Manual Style Management
For more control over when styles are injected:
use *;
use ;
3. Inline CSS
No external file needed:
use *;
use css;
4. Function-like Component Macro
Alternative syntax for defining styled components:
use *;
use component_with_css;
component_with_css!
How It Works
Compile-Time Processing
let css = scoped_style!;
// Generates: "sc_a1b2c3d4"
Input CSS:
}
}
Output (scoped):
}
}
Usage in Components
// Use the scoped class name
button
// Renders: <button class="sc_a1b2c3d4_btn">Click</button>
Style Injection Strategies
Auto-Injection (Recommended for Simple Cases)
Manual Injection (Recommended for Root Component)
Advanced Features
CSS File Path Resolution
The library searches for CSS files in multiple locations:
scoped_style!
// Searches:
// 1. ./button.css
// 2. ../button.css
// 3. ../../button.css
// 4. src/button.css
Minification
In release builds, CSS is automatically minified:
// Debug: Preserves formatting for readability
// Release: Removes whitespace and comments for smaller bundles
Hash Generation
Uses xxHash (XXH3) for fast, collision-resistant hashing:
// Hash includes file path + content for uniqueness
// Format: "sc_" + base62(hash)
// Example: "sc_3xK9mP2"
Performance Characteristics
- Compile-time processing: Zero runtime CSS parsing
- O(1) style lookups: HashMap-based registry
- Deduplication: Identical styles registered only once
- Fast hashing: xxHash3 is one of the fastest non-cryptographic hashes
- Efficient scoping: Single-pass CSS transformation
Architecture
┌─────────────────────────────────────┐
│ Your Component (compile time) │
│ scoped_style!("button.css") │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Procedural Macro │
│ • Read CSS file │
│ • Generate hash (xxHash3) │
│ • Scope selectors (.btn → .sc_xxx_btn)│
│ • Minify (release builds) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Runtime Registry (lazy_static) │
│ • Store scoped CSS │
│ • Deduplicate by hash │
│ • Preserve insertion order │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ inject_styles() → <style> tag │
│ • Inject into DOM │
│ • All styles in single tag │
└─────────────────────────────────────┘
Examples
Complete App Structure
use *;
use ;
Limitations
- Only class selectors are scoped (
.class) - ID selectors (
#id) and element selectors (div) remain global - Pseudo-classes (
:hover,:focus) are supported - Complex selectors work:
.btn > .icon,.card + .card
Troubleshooting
CSS file not found
// ❌ Error: Failed to find CSS file 'button.css'
scoped_style!
// ✅ Solution: Use relative path from Cargo.toml location
scoped_style!
Styles not appearing
// ❌ Forgot to inject styles
// ✅ Add inject_styles() to root component
Class name doesn't match
// CSS file
.button
// ❌ Wrong class name
button
// ✅ Match the class name exactly
button
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Credits
Built for the Dioxus framework.
Made with ❤️ for the Dioxus community