| Crates.io | masonry |
| lib.rs | masonry |
| version | 0.4.0 |
| created_at | 2022-11-30 04:57:11.158628+00 |
| updated_at | 2025-10-29 10:11:50.653117+00 |
| description | Traits and types of the Masonry toolkit. |
| homepage | |
| repository | https://github.com/linebender/xilem |
| max_upload_size | |
| id | 725908 |
| size | 830,769 |
Masonry is a foundational framework for building GUI libraries in Rust.
The developers of Masonry are developing Xilem, a reactive UI library built on top of Masonry. Masonry's API is geared towards creating GUI libraries; if you are creating an application, we recommend also considering Xilem.
Masonry gives you a platform-independent manager, which owns and maintains a widget tree. It also gives you tools to inspect that widget tree at runtime, write unit tests on it, and generally have an easier time debugging and maintaining your app.
The framework is not opinionated about what your user-facing abstraction will be: you can implement immediate-mode GUI, the Elm architecture, functional reactive GUI, etc., on top of Masonry.
It is opinionated about its internals: things like text focus, pointer interactions and accessibility events are often handled in a centralized way.
Masonry is built on top of:
Masonry can be used with any windowing library which allows the window content to be rendered using wgpu.
There are currently two backends for using Masonry to create operating system windows:
masonry_android_view for Android. This can currently be found in the Android View repository,
and is not yet generally usable.The to-do-list example looks like this, using masonry_winit as the backend:
use masonry::core::{ErasedAction, NewWidget, Properties, Widget, WidgetId, WidgetTag};
use masonry::dpi::LogicalSize;
use masonry::peniko::color::AlphaColor;
use masonry::properties::Padding;
use masonry::properties::types::Length;
use masonry::theme::default_property_set;
use masonry::widgets::{Button, ButtonPress, Flex, Label, Portal, TextAction, TextArea, TextInput};
use masonry_winit::app::{AppDriver, DriverCtx, NewWindow, WindowId};
use masonry_winit::winit::window::Window;
const TEXT_INPUT_TAG: WidgetTag<TextInput> = WidgetTag::new("text-input");
const LIST_TAG: WidgetTag<Flex> = WidgetTag::new("list");
const WIDGET_SPACING: Length = Length::const_px(5.0);
struct Driver {
next_task: String,
window_id: WindowId,
}
impl AppDriver for Driver {
fn on_action(
&mut self,
window_id: WindowId,
ctx: &mut DriverCtx<'_, '_>,
_widget_id: WidgetId,
action: ErasedAction,
) {
debug_assert_eq!(window_id, self.window_id, "unknown window");
if action.is::<ButtonPress>() {
let render_root = ctx.render_root(window_id);
render_root.edit_widget_with_tag(TEXT_INPUT_TAG, |mut text_input| {
let mut text_area = TextInput::text_mut(&mut text_input);
TextArea::reset_text(&mut text_area, "");
});
render_root.edit_widget_with_tag(LIST_TAG, |mut list| {
let child = Label::new(self.next_task.clone()).with_auto_id();
Flex::add_child(&mut list, child);
});
} else if action.is::<TextAction>() {
let action = action.downcast::<TextAction>().unwrap();
match *action {
TextAction::Changed(new_text) => {
self.next_task = new_text.clone();
}
TextAction::Entered(_) => {}
}
}
}
}
/// Return initial to-do-list without items.
pub fn make_widget_tree() -> NewWidget<impl Widget> {
let text_input = NewWidget::new_with_tag(
TextInput::new("").with_placeholder("ex: 'Do the dishes', 'File my taxes', ..."),
TEXT_INPUT_TAG,
);
let button = NewWidget::new(Button::with_text("Add task"));
let list = Flex::column()
.with_child(NewWidget::new_with_props(
Flex::row()
.with_flex_child(text_input, 1.0)
.with_child(button),
Properties::new().with(Padding::all(WIDGET_SPACING.get())),
))
.with_spacer(WIDGET_SPACING);
NewWidget::new(Portal::new(NewWidget::new_with_tag(list, LIST_TAG)))
}
fn main() {
let window_size = LogicalSize::new(400.0, 400.0);
let window_attributes = Window::default_attributes()
.with_title("To-do list")
.with_resizable(true)
.with_min_inner_size(window_size);
let driver = Driver {
next_task: String::new(),
window_id: WindowId::next(),
};
let event_loop = masonry_winit::app::EventLoop::with_user_event()
.build()
.unwrap();
masonry_winit::app::run_with(
event_loop,
vec![
NewWindow::new_with_id(
driver.window_id,
window_attributes,
make_widget_tree().erased(),
)
.with_base_color(AlphaColor::from_rgb8(2, 6, 23)),
],
driver,
default_property_set(),
)
.unwrap();
}
Running this will open a window that looks like this:

The following crate feature flags are available:
tracy: Enables creating output for the Tracy profiler using tracing-tracy.
This can be used by installing Tracy and connecting to a Masonry with this feature enabled.testing: Re-exports the test harness from [masonry_testing].Masonry apps currently ship with several debugging features built in:
If you want to use your own subscriber, simply set it before starting masonry - in this case masonry will not set a subscriber.
This version of Masonry has been verified to compile with Rust 1.88 and later.
Future versions of Masonry might increase the Rust version requirement. It will not be treated as a breaking change and as such can even happen with small patch releases.
Discussion of Masonry development happens in the Linebender Zulip, specifically the #masonry channel. All public content can be read without logging in.
Contributions are welcome by pull request. The Rust code of conduct applies.
Licensed under the Apache License, Version 2.0 (LICENSE or http://www.apache.org/licenses/LICENSE-2.0)