DEV Community

venand
venand

Posted on

Pure Rust GUI Landscape

Out of all programming languages, aside from javascript, Rust is currently seeing a flurry of crossplatform gui frameworks.
This is due to a combination of factors such as Rust's safety guarantees as well as its high performance.
In this article, we'll be looking at the most promising frameworks out there. Non-pure gui such libraries will not be discussed here.
The reason is that pure Rust guis are easier to build, since they don't require external C/C++ libraries. They are also safer by default given Rust's safety guarantees, and probably faster than frameworks written in other languages since Rust offers greater optimizability due to its guarantees.

Orbtk

Orbtk started its development with the redox operating system, an operating system written entirely in Rust. It's based on an ECS (entity-component system) and provides a functional reactive api.
It has above 3k stars on Github.
A code sample:

use orbtk::prelude::*;

fn main() {
      Application::new()
        .window(|ctx| {
            Window::new()
                .title("OrbTk - minimal example")
                .position((100.0, 100.0))
                .size(420.0, 730.0)
                .child(TextBlock::new().text("OrbTk").build(ctx))
                .build(ctx)
        })
        .run();
}
Enter fullscreen mode Exit fullscreen mode

And an example of the look of the toolkit:
image

slint

Allows developing fluid graphical user interfaces for any display, including embedded devices. It was started by 2 lead Qt developers.
It has 5k stars on Github. It's charactarized by having its own markup language.
Example:

HelloWorld := Window {
    width: 400px;
    height: 400px;

    Text {
       y: parent.width / 2;
       x: parent.x + 200px;
       text: "Hello, world";
       color: blue;
    }
}
Enter fullscreen mode Exit fullscreen mode

It aims to be as close as possible to native look and feel.

image

One downside of slint is its licensing model. It has a dual license, a permissive license for free open source projects, and a paid license for closed-source projects. The licensing fee is also quite steep last I checked

Dioxus

Dioxus is probably the only Rust gui framework which can target web, mobile and desktop platforms. It can also be used for terminal apps!
It has 5k stars on Github.
The api is similar to React:

fn app(cx: Scope) -> Element {
    let mut count = use_state(&cx, || 0);

    cx.render(rsx! {
        h1 { "High-Five counter: {count}" }
        button { onclick: move |_| count += 1, "Up high!" }
        button { onclick: move |_| count -= 1, "Down low!" }
    })
}
Enter fullscreen mode Exit fullscreen mode

Which should make it easy to onboard webdevelopers into Rust.

azul

Azul is a free, functional, reactive GUI framework. It uses firefox's WebRender rendering engine, written in Rust, and thus html5 and javascript can be used for the frontend.
It also has 5k stars on Github.

Example code:

use azul::prelude::*;
use azul::widgets::{button::Button, label::Label};

struct DataModel {
    counter: usize,
}

extern "C" 
fn render_dom(data: &mut RefAny, _: &mut LayoutInfo) -> StyledDom {

    let data = data.downcast_ref::<DataModel>()?;

    let label = Dom::text(format!("{}", data.counter))
        .with_inline_style("font-size: 50px;");

    let button = Button::new("Increment counter")
        .onmouseup(increment_counter, data.clone());

    Dom::body()
    .with_child(label)
    .with_child(button.dom())
    .style(Css::empty())
}

extern "C" 
fn increment_counter(data: &mut RefAny, _: &mut CallbackInfo) -> Update {
    let mut data = data.downcast_mut::<DataModel>()?;
    data.counter += 1;
    Update::RefreshDom // call render_dom() again
}

fn main() {
    let initial_data = RefAny::new(DataModel { counter: 0 });
    let app = App::new(initial_data, AppConfig::default());
    app.run(WindowCreateOptions::new(render_dom));
}
Enter fullscreen mode Exit fullscreen mode

Example look:
image

Druid

By world-renouned developer Raph levien, who's an authority on gui programming and creating gui frameworks.
The project has 8k stars on Github. It's used by some high profile and highly successful applications (also by Raph) such as piet, xi-editor and lapce editor.
It's charactarized by being "data-first".
Example api:

use druid::widget::{Button, Flex, Label};
use druid::{AppLauncher, LocalizedString, PlatformError, Widget, WidgetExt, WindowDesc};

fn main() -> Result<(), PlatformError> {
    let main_window = WindowDesc::new(ui_builder());
    let data = 0_u32;
    AppLauncher::with_window(main_window)
        .log_to_console()
        .launch(data)
}

fn ui_builder() -> impl Widget<u32> {
    // The label text will be computed dynamically based on the current locale and count
    let text =
        LocalizedString::new("hello-counter").with_arg("count", |data: &u32, _env| (*data).into());
    let label = Label::new(text).padding(5.0).center();
    let button = Button::new("increment")
        .on_click(|_ctx, data, _env| *data += 1)
        .padding(5.0);

    Flex::column().with_child(label).with_child(button)
}
Enter fullscreen mode Exit fullscreen mode

Example screenshots:
image

egui

Is an easy-to-use immediate mode GUI in Rust that runs on both web and native. It's light on resources and very high performance. Usually immediate-mode guis are used for games, however egui is a very viable option for general purpose gui.
It currently has 11k stars on Github.

Example code:

ui.heading("My egui Application");
ui.horizontal(|ui| {
    ui.label("Your name: ");
    ui.text_edit_singleline(&mut name);
});
ui.add(egui::Slider::new(&mut age, 0..=120).text("age"));
if ui.button("Click each year").clicked() {
    age += 1;
}
ui.label(format!("Hello '{}', age {}", name, age));
Enter fullscreen mode Exit fullscreen mode

Example look:
image

However, to myself, the most impressive is egui's online demo.

Iced

Is an elm-inspired framework. It currently has 17k stars on Github. It's a high performance gui which uses wgpu for rendering. wgpu also allows it to run in your browser.
Example api:

use iced::widget::{button, column, text, Column};

impl Counter {
    pub fn view(&self) -> Column<Message> {
        // We use a column: a simple vertical layout
        column![
            // The increment button. We tell it to produce an
            // `IncrementPressed` message when pressed
            button("+").on_press(Message::IncrementPressed),

            // We show the value of the counter here
            text(self.value).size(50),

            // The decrement button. We tell it to produce a
            // `DecrementPressed` message when pressed
            button("-").on_press(Message::DecrementPressed),
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

Example look:
image

This framework is probably the most mature and functional in the Rust ecosystem and is very actively developed, it's used in cryptowatch desktop:
image

Tauri

Tauri is a better alternative to Electron, where the backend is written purely in Rust. For the frontend, html5 and javascript can be used.
It has a whopping 54k stars on github. It offers better performance than electron and a smaller binary size. There is also work on adding an iOS and android target, which electron doesn't support.

image

Starting a Tauri project is also easier than the previously mentioned frameworks:

npm create tauri-app
Enter fullscreen mode Exit fullscreen mode

The tauri cli tool also allows you to easily create installers for your binary.

Conclusion

It seems all the stars aligned and currently point at Tauri. If you have a webdev background, it would be the perfect choice for getting started with gui programming in Rust.
That said, don't miss out on the other listed projects. Personally, I'm keeping an eye on Druid, which seems to be the most successful non-webtech project, that's also being developed by Mr Levien.
If however you're targetting a game engine, then your only option at the moment is egui.

Top comments (0)