Rust GUI frameworks
2022 Framework 2026: Powers Zed; small outside ecosystem
18

gpui: Zed’s framework

A GUI framework built to make an editor fast.

gpui is the UI framework behind the Zed editor. Views are structs that implement Render. Their render method returns a tree of div()s styled with a Tailwind-like vocabulary: .flex(), .gap_2(), .bg(...). Mutating state is explicit, and you call cx.notify() to say "this view changed, render it again."

gpui-hello/src/bin/one.rs ✔ compiled · gpui 0.2 · rustc 1.95.0
use book_error::Error;
use gpui::{App, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size};

struct Counter {
    count: u32,
}

impl Render for Counter {
    // Called whenever the entity is marked dirty; returns a tree of styled divs
    // using Tailwind-like methods. Taffy lays it out; GPUI paints it.
    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .flex()
            .size_full()
            .justify_center()
            .items_center()
            .bg(rgb(0x1e1e2e))
            .text_color(rgb(0xffffff))
            .child(
                div()
                    .id("inc")
                    .p_4()
                    .bg(rgb(0x45475a))
                    .rounded_md()
                    .child(format!("clicked {} times", self.count))
                    .on_click(cx.listener(|this, _event, _window, cx| {
                        this.count += 1;
                        cx.notify(); // tell GPUI this view needs to re-render
                    })),
            )
    }
}

fn main() {
    Application::new().run(|cx: &mut App| {
        let bounds = Bounds::centered(None, size(px(400.), px(300.)), cx);
        let options = WindowOptions { window_bounds: Some(WindowBounds::Windowed(bounds)), ..Default::default() };
        // The startup closure returns (), so report the failure and quit the app.
        if let Err(e) = cx.open_window(options, |_, cx| cx.new(|_| Counter { count: 0 })) {
            eprintln!("{}", Error::other(e).report());
            cx.quit();
            return;
        }
        cx.activate(true);
    });
}

The styling methods are not CSS. Each one sets a Taffy style, and Taffy computes the layout before gpui paints. gpui depends directly on taffy (0.9.0), cosmic-text (0.14.2), lyon (tessellation) and resvg, and it has no winit: it has its own platform layers (Metal on macOS, plus Windows, X11 and Wayland backends).

gpui-hello/src/bin/two.rs ✔ compiled · gpui 0.2 · rustc 1.95.0
use book_error::Error;
use gpui::{App, Application, Context, Window, div, prelude::*, rgb};

// The same Tailwind-style vocabulary works for any layout. Under the hood,
// every `flex()` / `gap_2()` call becomes a Taffy style.
struct Toolbar;

impl Render for Toolbar {
    fn render(&mut self, _w: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .flex()
            .flex_row()
            .gap_2()
            .p_2()
            .bg(rgb(0x181825))
            .children(["File", "Edit", "View"].map(|name| {
                div().px_3().py_1().rounded_sm().hover(|s| s.bg(rgb(0x313244))).child(name)
            }))
    }
}

fn main() {
    Application::new().run(|cx: &mut App| {
        if let Err(e) = cx.open_window(Default::default(), |_, cx| cx.new(|_| Toolbar)) {
            eprintln!("{}", Error::other(e).report());
            cx.quit();
        }
    });
}

A caution about versions. The gpui on crates.io (0.2.x, published October 2025) is behind Zed's own repository: its lockfile still resolves the Blade graphics library, while Zed moved Linux rendering to wgpu in February 2026. On macOS it also compiles Metal shaders at build time, which needs Xcode's shader toolchain; the snippet above uses the runtime_shaders feature to defer that. Both examples compile against gpui 0.2.2 from crates.io. The startup closure returns nothing, so a failed open_window is reported and the app quits rather than panicking.

crates.io first publish. Check Zed’s own announcement for the real public date.