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, IDs, and elements are automatically scoped
- 🏷️ Element Scoping - Element selectors (
div,span) use data attributes for isolation - 📦 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.2.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 and data-scope attribute
button
// Renders: <button data-scope="sc_a1b2c3d4" class="sc_a1b2c3d4_btn">Click</button>
Scoping Behavior
What Gets Scoped
| Selector Type | Input | Output | Usage |
|---|---|---|---|
| Class | .btn |
.sc_xxx_btn |
class: "{css}_btn" |
| ID | #header |
#sc_xxx_header |
id: "{css}_header" |
| Element | div |
div[data-scope="sc_xxx"] |
"data-scope": "{css}" |
| Pseudo-class | .btn:hover |
.sc_xxx_btn:hover |
(automatic) |
| Complex | .card > .title |
.sc_xxx_card > .sc_xxx_title |
(automatic) |
Element Scoping (New in v0.2.0)
Elements are scoped using data-scope attributes:
// CSS
div
span.highlight
// Component
rsx!
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
Complex Selectors
All complex selectors are fully supported:
/* Child combinator */
}
/* Output: .sc_xxx_parent > .sc_xxx_child { color: blue; } */
/* Adjacent sibling */
}
/* Output: .sc_xxx_card + .sc_xxx_card { margin-top: 20px; } */
/* Mixed selectors */
}
/* Output: div[data-scope="sc_xxx"].sc_xxx_container > span[data-scope="sc_xxx"]#sc_xxx_label { font-weight: bold; } */
/* Pseudo-classes */
}
/* Output: button[data-scope="sc_xxx"]:hover:active { transform: scale(0.95); } */
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 with optimized state machine
Architecture
┌─────────────────────────────────────┐
│ Your Component (compile time) │
│ scoped_style!("button.css") │
└──────────────┬──────────────────────┘
↓
┌─────────────────────────────────────┐
│ Procedural Macro │
│ • Read CSS file │
│ • Generate hash (xxHash3) │
│ • Scope selectors: │
│ - .btn → .sc_xxx_btn │
│ - #id → #sc_xxx_id │
│ - div → div[data-scope="sc_xxx"] │
│ • 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 ;
Scoping Rules Summary
✅ Automatically Scoped
- Classes:
.button→.sc_xxx_button - IDs:
#header→#sc_xxx_header - Elements:
div→div[data-scope="sc_xxx"](requiresdata-scopeattribute) - Pseudo-classes:
:hover,:focus,:active, etc. - Pseudo-elements:
::before,::after - Attribute selectors:
[type="text"](passed through, element gets scoped) - Complex selectors: All combinators (
>,+,~, space)
❌ Not Scoped (Global)
- Universal selector:
* - :root: CSS variables at root level
- @keyframes: Animation definitions (use unique names)
- @media, @supports: Query blocks (contents are scoped)
Migration from v0.1.0
Breaking Changes in v0.2.0
-
Element selectors now require
data-scope:// OLD (v0.1.0) - elements were not scoped rsx! // NEW (v0.2.0) - add data-scope rsx! -
Class selector output format changed:
- Old:
.sc_xxx.button - New:
.sc_xxx_button
- Old:
-
ID selector output format changed:
- Old:
#sc_xxx.header - New:
#sc_xxx_header
- Old:
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
Element styles not working (v0.2.0)
// ❌ Missing data-scope attribute
div
// ✅ Add data-scope for element scoping
div
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. See CONTRIBUTING.md for guidelines.
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.
Changelog
See CHANGELOG.md for detailed version history.
Made with ❤️ for the Dioxus community