Expand description
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:
- Vello and wgpu for 2D graphics.
- Parley for the text stack.
- AccessKit for plugging into accessibility APIs.
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_winit for most platforms.
masonry_android_viewfor Android. This can currently be found in the Android View repository, and is not yet generally usable.
§Example
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:

§Feature flags
The following crate feature flags are available:
tracy: Enables creating output for the Tracy profiler usingtracing-tracy. This can be used by installing Tracy and connecting to a Masonry with this feature enabled.testing: Re-exports the test harness frommasonry_testing.
§Debugging features
Masonry apps currently ship with several debugging features built in:
- A rudimentary widget inspector - toggled by the F11 key.
- A debug mode painting widget layout rectangles - toggled by the F12 key.
- Optional automatic registration of a tracing subscriber, which outputs to the console and to a file in the dev profile.
If you want to use your own subscriber, simply set it before starting masonry - in this case masonry will not set a subscriber.
Re-exports§
pub use accesskit;pub use vello::kurbo;pub use vello::peniko;pub use dpi;pub use parley;pub use vello;pub use masonry_testing as testing;testingpub use ui_events;
Modules§
- app
- Types needed for running a Masonry app.
- core
- Basic types and traits Masonry is built on.
- doc
- Documentation-only module
- palette
- Palettes with predefined colors.
- properties
- Types and logic commonly used across widgets.
- theme
- Default values used by various widgets in their paint methods.
- util
- Miscellaneous utility functions.
- widgets
- Common widgets.
Structs§
- Text
Align Options - Additional options to fine tune alignment
Enums§
- Text
Align - Alignment of a layout.