maud-extensions
Small, local superpowers for Maud.
Install
If you want the experimental component system too:
If you want the crate to read as mx::... at call sites without renaming the
published crate:
or in Cargo.toml:
[]
= { = "maud-extensions", = "0.6.0" }
Core Story
Write plain html! and emit local CSS and JS where they belong:
use html;
use ;
This is still the intended center of gravity:
- no wrapper component macro
- no hidden CSS/JS injection
- no stringly helper names
- plain Maud remains the main language
Experimental Components
The component system is opt-in behind the components feature.
Preferred authoring pattern:
use ;
use ;
What this gives you:
- Bon-backed typed builders
Slot<Markup>andSlot<Vec<Markup>>as the slot declaration path#[mx(default)]for the single default slot#[mx::component] implblocks with colocated:render! { ... }css! { ... }js!(once, { ... })
- builder
.render()automatically includes impl-local CSS and JS in the rendered root
Current constraints:
- use
Slot<T>instead of#[mx(slot)] - if there are multiple slot fields, mark exactly one
#[mx(default)] - repeated slots use
Slot<Vec<T>>plus#[mx(each = item_name)] #[mx::component]impls currently allow:- exactly one
render! - at most one
css! - at most one
js!
- exactly one
Mental model:
#[derive(Component)]owns fields, slots, and the Bon-backed builder#[mx::component]owns the render root and colocated CSS/JS blocks- builder
.render()goes through the hiddenComponentRenderhook produced by the impl macro
This keeps the builder and the impl-local render/assets story explicit without
requiring manual (Self::css()) / (Self::js()) emission in the render body.
If you want a more minimal component style, you can still stop at plain
html! + css! + js!. The component system is intentionally a second layer,
not the only way to use the crate.
Named Helpers
When reuse helps, define local helper functions with Rust identifiers:
use html;
use ;
css!;
js!;
Supported css! forms:
css! { ... }css!(name, { ... })
Supported js! forms:
js! { ... }js!(once, { ... })js!(name, { ... })js!(name, once, { ... })
CSS Helper Macros
Inside css! token mode you can use:
raw!(r#"..."#)media!(prelude, { ... })container!(prelude, { ... })supports!(prelude, { ... })layer!(prelude, { ... })keyframes!(prelude, { ... })- unit helpers:
rem!(...)em!(...)px!(...)pct!(...)vw!(...)vh!(...)ms!(...)s!(...)
Example:
use css;
Limits
css!andjs!are placement-sensitive local emittersjs!(once, ...)relies on adata-mx-js-ranmarker on the parent element- CSS token mode only sees Rust-tokenizable input; use
raw!(...)for arbitrary CSS fragments - JavaScript is validated with SWC before emission
- CSS is checked for lightweight syntax and raw-text safety before emission