Xilem: the Linebender rewrite
Reactive views on top of Masonry, Vello and Parley.
Xilem is the Linebender team's successor to Druid, and it splits into three layers. Xilem proper is a reactive view layer: a pure function from your state to a lightweight description of the UI, which it diffs on each change. Masonry is the retained widget toolkit underneath. Vello and Parley draw and lay out text. A counter looks like this.
use book_error::Result;
use xilem::view::{flex_col, label, text_button};
use xilem::{EventLoop, WidgetView, WindowOptions, Xilem};
struct AppState {
count: i32,
}
// A pure function from state to a view description. Xilem diffs the
// descriptions and updates the retained widgets (Masonry) underneath.
fn app_logic(state: &mut AppState) -> impl WidgetView<AppState> + use<> {
flex_col((
label(format!("count: {}", state.count)),
text_button("increment", |state: &mut AppState| state.count += 1),
))
}
fn main() -> Result<()> {
let app = Xilem::new_simple(AppState { count: 0 }, app_logic, WindowOptions::new("Counter"));
app.run_in(EventLoop::with_user_event())?;
Ok(())
} State can be split into reusable components that each see only one field, using lens, a descendant of Druid's Lens. The component below knows nothing about likes or dislikes; it only edits a u32. (The + use<> in the signatures is Rust's precise-capturing syntax, which the crate's own examples use.)
use book_error::Result;
use xilem::core::lens;
use xilem::view::{flex_row, label, text_button};
use xilem::{EventLoop, WidgetView, WindowOptions, Xilem};
#[derive(Default)]
struct AppState {
likes: u32,
dislikes: u32,
}
// A reusable component that only knows about the slice of state it edits.
fn votes(n: &mut u32) -> impl WidgetView<u32> + use<> {
flex_row((label(format!("votes: {n}")), text_button("+", |n: &mut u32| *n += 1)))
}
// `lens` focuses the component on one field, like Druid's Lens did.
fn app_logic(_state: &mut AppState) -> impl WidgetView<AppState> + use<> {
flex_row((
lens(votes, |s: &mut AppState| &mut s.likes),
lens(votes, |s: &mut AppState| &mut s.dislikes),
))
}
fn main() -> Result<()> {
Xilem::new_simple(AppState::default(), app_logic, WindowOptions::new("Votes"))
.run_in(EventLoop::with_user_event())?;
Ok(())
} Its crates.io dependencies are masonry, masonry_winit, vello and winit. In our lockfile that resolves Vello 0.6.0, Parley 0.6.0, AccessKit 0.21.1 and wgpu 26.0.1, all older than each crate's latest release, because Xilem 0.4 was released against them. It is the clearest example of a framework that sits on top of shared layers and lags them by several versions. Xilem is at 0.4.0, pre-1.0, with 6 dependent crates.