iet-ui
Renders escaped inline components and assets; transport choices stay in the adapter.
iet-uibuilding blocksTyped HTML building blocksHow to use it
iet-ui renders typed, HTML-escaped markup with the html! macro and returns Markup, a value that converts into any response body. It ships transport-neutral components and a bundle_hash for cache-busting compiled assets, so server-rendered pages in iet-http-htmx-axum apps share one escaping and asset story.
// examples/htmx-starter/crates/task-adapter-htmx/src/pages.rs
use ;
- Interpolations are escaped;
html!moves straight into the response buffer, so static markup reserves exactly its byte count. iet_ui::componentsoffersnotice,validation_errors,search,pagination,table,disclosure,dialog, andcsrf_field.Markup::into_string()/.as_str()convert to text;bundle_hash(&[("app.js", bytes)])fingerprints a name+bytes set for asset URLs.
How it works
The html! macro expands structured markup into a Markup, a wrapper around one output String; dynamic values are routed through text! and write_escaped so interpolation can never inject raw markup. Markup implements the Render trait, so it can be rendered straight into a response body, and bundle_hash fingerprints an asset set for cache-busting URLs.
flowchart LR A["html! macro"] --> B["Markup"] C["text! macro"] --> D["write_escaped"] D --> B B --> E["Render"] E --> F["into_string"] F --> G["HTTP response body"] H["bundle_hash"] --> I["fingerprinted asset URL"]
What it implements
- Concrete mechanism; see the public API below.
What's inside
Modules
src/components.rssrc/lib.rssrc/markup.rssrc/script.rs
Public API
(root)
pub fn bundle_hash(assets: &[(&str, &[u8])]) -> String— A bundle fingerprint covers both names and bytes; changing any asset changes URLs.
components
pub fn notice(message: &str, error: bool) -> Markuppub fn validation_errors(errors: &[&str]) -> Markuppub fn search(action: &str, target: &str, query: &str) -> Markup— GET search with delayed HTMX refresh and a native submit fallback.pub fn pagination(previous: Option<&str>, next: Option<&str>, target: &str) -> Markup— Caller computes safe pagination URLs, retaining filters/sort parameters.pub fn table(caption: &str, columns: &[&str], rows: &[Vec<String>]) -> Markup— Cells are text-only; use application components for trusted interactive cells.pub fn disclosure(title: &str, content: Markup) -> Markup— Native disclosure rather than a fake modal: keyboard-accessible without JS.pub fn dialog(id: &str, title: &str, content: Markup) -> Markup— A real modal dialog; callers open it usingshowModal()from their own script. Closing is native; focus trapping/escape semantics are supplied by the browser.pub fn csrf_field(token: &str) -> Markup
markup
- struct
Markup - const
fn— Borrow compile-time HTML without allocating a render buffer. pub fn is_static(&self) -> boolpub fn into_cow(self) -> Cow<'static, str>— Preserve static storage or move the owned render buffer into a transport.pub fn from_rendered(value: String) -> Self— Only pass already escaped/trusted HTML. Prefer html! for application rendering.pub fn into_string(self) -> Stringpub fn as_str(&self) -> &str- struct
StaticView - const
fn - const
fn - const
fn - trait
Render— Statically dispatched child rendering. Iterators are consumed without collecting.
pub fn write_escaped(output: &mut String, value: &impl fmt::Display)
script
- struct
Script - const
fn - const
fn - const
fn - struct
Component pub fn new(content: crate::Markup, script: &Script) -> Selfpub fn with_props(mut self, props: &impl serde::Serialize) -> Result<Self, serde_json::Error>
Impl map
AsRef<str> for MarkupFrom<StaticView> for MarkupRender for StaticViewfmt::Display for MarkupRender for MarkupRender for TWrite for Escaped<'_>crate::Render for Component
Depends on
External crates: serde, serde_json, sha2
Cargo features
scripts— iet-ui-macros/scripts, dep:serde, dep:serde_json
Used by
In this repository
examples/htmx-starterexamples/skills-only-app-task-tracker
Source: crates/features/iet-ui