crates.io ↗

iet-ui

feature building blocks official

Renders escaped inline components and assets; transport choices stay in the adapter.

CoreFeaturesIntegrationsStacksTooling
Used byiet-auth-login-htmx-axumiet-http-htmx-axum
iet-uibuilding blocksTyped HTML building blocks
Depends oniet-ui-macroscontract

How 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.

rust
// examples/htmx-starter/crates/task-adapter-htmx/src/pages.rs
use iet_ui::{Markup, html};

pub fn layout(content: Markup) -> Markup {
    html! { <!DOCTYPE html><html lang="en"><head><meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Fieldnotes - projects and tasks</title><link rel="stylesheet" href="/app.css" />
        <script defer src="/htmx.js"></script><script defer src="/app.js"></script>
    </head><body><main>{content}</main></body></html> }
}
  • Interpolations are escaped; html! moves straight into the response buffer, so static markup reserves exactly its byte count.
  • iet_ui::components offers notice, validation_errors, search, pagination, table, disclosure, dialog, and csrf_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.rs
  • src/lib.rs
  • src/markup.rs
  • src/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) -> Markup
  • pub fn validation_errors(errors: &[&str]) -> Markup
  • pub 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 using showModal() 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) -> bool
  • pub 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) -> String
  • pub fn as_str(&self) -> &str
  • struct StaticView
  • const fn
  • const fn
  • const fn
  • trait Render — Statically dispatched child rendering. Iterators are consumed without collecting.
rust
pub trait Render {
    fn render_into(self, output: &mut String);
}
  • 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) -> Self
  • pub fn with_props(mut self, props: &impl serde::Serialize) -> Result<Self, serde_json::Error>

Impl map

  • AsRef<str> for Markup
  • From<StaticView> for Markup
  • Render for StaticView
  • fmt::Display for Markup
  • Render for Markup
  • Render for T
  • Write 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-starter
  • examples/skills-only-app-task-tracker

Source: crates/features/iet-ui