Expand description
§iced-markup
A declarative markup DSL (Domain-Specific Language) for building Iced GUI applications in Rust.
Instead of writing deeply nested builder chains by hand, you write a
concise, JSX-inspired syntax inside the view! macro and get
idiomatic Iced widget code at compile time — zero runtime overhead.
§Quick example
use iced::widget::{column, row, text, button};
use iced_markup::view;
#[derive(Clone)]
enum Msg { Click }
fn view() -> iced::Element<'static, Msg> {
view! {
column ![spacing: 20, padding: 40] {
text("Welcome to Iced!") {},
row ![spacing: 10] {
button("Increment") ![on_press: Msg::Click] {},
button("Decrement") ![on_press: Msg::Click] {},
},
}
}
.into()
}§Advanced Features
iced_markup provides several advanced features to simplify complex UIs:
§1. Native Control Flow
Use real if and for blocks inside your markup:
let _: Column<'_, Msg, Theme, Renderer> = view! {
column {
if show_admin {
text("Admin Panel") {}
},
for item in items {
text(item) {}
}
}
};§2. Thematic Pipes (|)
Apply styles or themes with a sleek syntax:
let _: Column<'_, Msg, Theme, Renderer> = view! {
column {
text("Hello") | |_: &Theme| iced::widget::text::Style { color: Some(iced::Color::WHITE) } {}
}
};§3. Event Shorthands (+)
Use +click, +input, or +submit for common events:
let _: Column<'_, Msg, Theme, Renderer> = view! {
column {
button("Save") ![+click: Msg::Save] {}
}
};§4. Component Slots (@)
Use named slots for flexible widget configuration:
let _: Column<'_, Msg, Theme, Renderer> = view! {
column {
button("Submit") {
@on_press: Msg::Click
}
}
};§Architecture
The crate is structured as a classic compiler pipeline:
- [
parser] — Reads the token stream and produces a typed AST. - [
node] — Defines every node type (widgets, attributes, control flow). - [
codegen] — ImplementsToTokensfor every AST node, emitting optimized Iced Rust code.
The public entry point is the view! procedural macro defined below.