![]() I've ignored most of the changes and the projects still compile and test fine. Changes I did commit: Add `+ use<>` after functions. Remove `ref mut` from some patterns. Bump MSRV. Apply new rustfmt format. |
||
---|---|---|
.. | ||
examples | ||
resources | ||
src | ||
Cargo.toml | ||
LICENSE | ||
README.md |
README.md
Xilem is a UI toolkit. It combines ideas from Flutter
, SwiftUI
, and Elm
.
Like all of these, it uses lightweight view objects, diffing them to provide
minimal updates to a retained UI. Like SwiftUI
, it is strongly typed.
The talk Xilem: Let's Build High Performance Rust UI by Raph Levien was presented at the RustNL conference in 2024, and gives a video introduction to these ideas. Xilem is implemented as a reactive layer on top of Masonry, a widget toolkit which is developed alongside Xilem. Masonry itself is built on top of a wide array of foundational Rust UI projects:
- Rendering is provided by Vello, a high performance GPU compute-centric 2D renderer.
- GPU compute infrastructure is provided by wgpu.
- Text layout is provided by Parley.
- Accessibility is provided by AccessKit (docs).
- Window handling is provided by winit.
Xilem can currently be considered to be in an alpha state. Lots of things need improvements (including this documentation!).
There is also a blog post from when Xilem was first introduced.
Example
A simple incrementing counter application looks like:
use winit::error::EventLoopError;
use xilem::view::{button, flex, label};
use xilem::{EventLoop, WidgetView, Xilem};
#[derive(Default)]
struct Counter {
num: i32,
}
fn app_logic(data: &mut Counter) -> impl WidgetView<Counter> + use<> {
flex((
label(format!("{}", data.num)),
button("increment", |data: &mut Counter| data.num += 1),
))
}
fn main() -> Result<(), EventLoopError> {
let app = Xilem::new(Counter::default(), app_logic);
app.run_windowed(EventLoop::with_user_event(), "Counter app".into())?;
Ok(())
}
A key feature of Xilem's architecture is that the application's state, in this case Counter
, is an arbitrary 'static
Rust type.
In this example, app_logic
is the root component, which creates the view value it returns.
This, in turn, leads to corresponding Masonry widgets being created, in this case a button and a label.
When the button is pressed, the number will be incremented, and then app_logic
will be re-ran.
The returned view will be compared with its previous value, which will minimally update the contents of these widgets.
As the num
field's value has changed, the label
's formatted text will be different.
This means that the label widget's text will be updated, updating the value displayed to the user.
In this case, because the button is the same, it will not be updated.
More examples can be found in the repository.
Note: The linked examples are for the main
branch of Xilem. If you are using a released version, please view the examples in the tag for that release.
Reactive layer
The core concepts of the reactive layer are explained in Xilem Core.
View elements
The primitives your Xilem
app’s view tree will generally be constructed from:
flex
: defines how items will be arranged in a row or columngrid
: divides a window into regions and defines the relationship between inner elements in terms of size and positionsized_box
: forces its child to have a specific width and/or heightbutton
: basic button elementimage
: displays a bitmap imageportal
: a scrollable regionprogress_bar
: progress bar elementprose
: displays immutable, selectable texttextbox
: allows text to be edited by the usertask
: launch an async task which will run until the view is no longer in the treezstack
: an element that lays out its children on top of each other
You should also expect to use the adapters from Xilem Core, including:
lens
: an adapter for using a component from a field of the current state.memoize
: allows you to avoid recreating views you know won't have changed, based on a key.
Minimum supported Rust Version (MSRV)
This version of Xilem has been verified to compile with Rust 1.85 and later.
Future versions of Xilem 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.
Click here if compiling fails.
As time has passed, some of Xilem's dependencies could have released versions with a higher Rust requirement. If you encounter a compilation issue due to a dependency and don't want to upgrade your Rust toolchain, then you could downgrade the dependency.
# Use the problematic dependency's name and version
cargo update -p package_name --precise 0.1.1
Community
Discussion of Xilem development happens in the Linebender Zulip, specifically the #xilem channel. All public content can be read without logging in.
Contributions are welcome by pull request. The Rust code of conduct applies.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache 2.0 license, shall be licensed as noted in the License section, without any additional terms or conditions.
License
Licensed under the Apache License, Version 2.0 (LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
Some files used for examples are under different licenses:
- The font file (
RobotoFlex-Subset.ttf
) inresources/fonts/roboto_flex/
is licensed solely as documented in that folder (and is not licensed under the Apache License, Version 2.0). - The data file (
status.csv
) inresources/data/http_cats_status/
is licensed solely as documented in that folder (and is not licensed under the Apache License, Version 2.0). - The data file (
emoji.csv
) inresources/data/emoji_names/
is licensed solely as documented in that folder (and is not licensed under the Apache License, Version 2.0).
Note that these files are not distributed with the released crate.