egui: an immediate mode GUI library for Rust
egui is a solid pick when you need a GUI bolted onto a Rust project fast, without wrestling a retained-mode widget tree. It trades native look and polish for callback-free code: click handling and app state end up in one function instead of scattered across handler wiring. That's the whole appeal, not extra power. The catch is the API isn't stable yet, so upgrading between releases can mean rewriting UI calls.
What is egui?
egui is a Rust library for building immediate mode graphical interfaces: each widget redraws and is checked fresh every frame, instead of living in a persistent tree with handlers attached. It runs on the web via WebAssembly, natively on desktop through eframe, and inside any renderer that draws textured triangles. You call into egui from your own render loop, not the other way around.
What egui offers
- โWidget set covers labels, buttons, checkboxes, radio buttons, sliders, draggable values, color pickers, spinners, and a text editor with copy/paste, undo, and emoji support.
- โLayout helpers for horizontal, vertical, column, and auto-wrapping arrangements, plus panels, collapsing headers, and scrollable regions.
- โMovable, resizable windows that auto-size and auto-position themselves.
- โThrough egui's own 2D graphics layer called epaint, it offers anti-aliased rendering for lines, circles, text, and convex polygons.
- โOptional accessibility support via AccessKit, covering native screen readers on Windows and macOS.
- โBuilt-in image display, with the egui_extras crate handling image loading so the core crate stays lean.
- โThe same UI code runs on native builds and on the web via WebAssembly without a rewrite.
Adding egui to your Rust project
The README doesn't spell out a single `cargo add egui` line; it points to two starting paths instead. For a desktop or web app, clone github.com/emilk/eframe_template and follow its instructions, which wire up eframe, the official framework, for you. To use egui bare, inside your own engine or renderer, the official docs at docs.rs/egui cover integrating it directly. There are also worked examples in the repo's examples/ folder. Building the demo app locally on Linux needs extra system packages first, libclang-dev, libgtk-3-dev, and a handful of libxcb/libxkbcommon/openssl dev packages, but that's a demo-app requirement, not something egui itself needs; the README is explicit that egui is platform-agnostic on its own.
Writing your first egui UI
A minimal egui UI reads like ordinary Rust control flow: no separate markup, no XML, and no builder object created ahead of time and wired to a callback: ```rust 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("Increment").clicked() { age += 1; } ui.label(format!("Hello '{name}', age {age}")); ui.image(egui::include_image!("ferris.png")); ``` Every line above runs again on the next frame; that's what "immediate mode" means. Nothing lingers between frames. The `if ui.button(...).clicked()` pattern replaces an on-click handler: you check the return value right where the button gets drawn, so app state (`name`, `age`) and UI state never drift apart.
Strengths
- โNo handler wiring: click handling sits right next to the widget that triggers it, which keeps small UIs easy to read.
- โThe README states there's no `unsafe` code in egui, and dependencies are kept minimal by design, with heavier stuff pushed into optional crates like egui_extras.
- โThe same UI code compiles to web (WASM) and native without a rewrite, matching the project's portability goal.
- โWidget IDs for interaction are generated automatically, so two buttons can share a label without colliding, a rough edge the README says Dear ImGui does have.
- โAlready used for production-feel tools: the README points to the Rerun Viewer as an example of a professional-looking egui app.
What egui explicitly does not do
- โณLayout is the classic immediate-mode headache: sizing a window before laying out its contents is a real paradox, and egui's fix, remembering size from the previous frame, causes a one-frame flicker the first time a window or grid appears.
- โณThe README states the interfaces are still in flux and that new releases will have breaking changes, so pinning a version matters.
- โณNative look and feel is an explicit non-goal; egui doesn't try to match your OS's widget style, so it always reads as "an egui app" rather than blending into Windows, macOS, or GNOME chrome.
- โณStyling is more limited than CSS-based UI systems today; the README itself says theming via `Context::set_style` doesn't yet match what CSS can do and flags it as an open issue.
- โณLarge scrollable regions get laid out every frame, so a very long scrollback list can visibly tax the CPU if you don't limit what renders off-screen.
Other Rust GUI libraries to consider
Frequently asked questions
egui compiles to WebAssembly and runs in any browser with WASM and WebGL support; the official web demo at egui.rs is built this way. The core egui crate is Wasm-friendly by design, and eframe handles the browser integration, input and canvas rendering, for you.
egui is the 2D UI library itself: it lays out and handles buttons, sliders, and other widgets but has no idea whether it's running on the web or natively, and doesn't collect input or draw to the screen. eframe is the official framework that supplies that missing piece, wiring up input and rendering for web and native targets.
egui doesn't handle async itself; the README warns that calling `.await` directly inside UI code freezes the interface, since a frame has to finish drawing without blocking. Instead you keep the UI thread non-blocking and pass results back through a channel, an `Arc<Mutex<T>>`, or a crate like `poll_promise` or `tokio::sync::watch`.
egui integrates with Bevy through the bevy_egui crate, which the egui project names directly as the common way to run egui inside a game engine such as Bevy. egui itself doesn't know it's inside Bevy; bevy_egui feeds it input and paints its output using Bevy's own renderer, instead of going through eframe.
egui supports non-Latin characters, but the README is clear that you need to install your own font, a `.ttf` or `.otf` file, through `Context::set_fonts`, since the default fonts don't cover every script. Colors, spacing, sizes, and fonts can also be customized globally via `Context::set_style`.
egui runs natively on Linux, Mac, and Windows, in the browser via WebAssembly, and, through eframe, its official framework, on Android as well. The core egui crate doesn't know which platform it's on; that's handled by whichever integration is rendering it, such as eframe, egui_glow, or egui-wgpu.
The problem it solves
Most Rust GUI crates ask you to pick a lane early: bind to a heavyweight native toolkit and deal with per-platform packaging quirks, or adopt a full framework with its own app lifecycle that dictates how your code is structured. Neither path lets you draw a UI from inside an existing render loop, a game engine's per-frame update, say, without extra glue. egui fills that narrow gap: a widget library you call directly from wherever you already draw, whether that's a bare wgpu renderer or a game engine's frame hook.
Best use cases
- โขDebug and inspector overlays for a game or simulation, drawn straight from Rust code each frame.
- โขSmall internal or hobby desktop utilities where shipping fast matters more than a native-looking UI.
- โขGame engine tooling, level editors, parameter panels, and debug HUDs wired in via bevy_egui or a custom integration.
- โขRust-only web apps compiled to WASM that need interactive controls without touching JavaScript.
Who should try it โ and who should skip
Try egui if you're a Rust developer who needs a debug panel, config screen, or lightweight tool UI shipped this week rather than styled to match the OS. It suits solo and small-team projects, game developers wiring up in-engine tooling, and anyone who'd rather write `if ui.button(...).clicked()` than manage handler objects. Skip it if you're not writing Rust, need a UI indistinguishable from native OS chrome, or can't tolerate breaking changes between releases; the README says the interfaces are still in flux.
Related repositories
Still deciding about egui?
One click hands the question to an AI along with this page โ see what it says about egui.
