NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
crates.io · #2890 most downloaded on crates.io
Default fonts for use in epaint / egui
Last release 1 months ago
08 Sep 2026
Ships fairly regularly
a new release about every 5 weeks
Nearly every release is documented
notes for 20 of 20 stable releases
Nothing withdrawn
no release was ever pulled
2 years old
20 releases · first in 2024
One column per month.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
window_title_frame to window_frame when unspecified #8400 by @rustbasicDragValue #8403 by @teddytennantmin_size in TextEdit #8420 by @lucasmerlinegui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
Sense::drag detecting drags when clicking widget above it #8396 by @lucasmerlinegui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
Autocomplete, autocorrect and IMEs now work correctly on iOS and android (on eframe web)!
ScreenRecording_08-05-2026.11-48-49_1.MP4You can now reopen closed panels by dragging the handle:
Screen.Recording.2026-08-05.at.11.45.10.movPreviously, when switching themes, the window chrome (OS titlebar), stayed in the OS theme. Now, it syncs with the app theme:
Screen.Recording.2026-08-05.at.11.45.47.movBoxedWidget: dynamically dispatched widgets #8378 by @emilkWidgetText::size #8377 by @emilkLayoutJob::clear #8376 by @emilkegui::Window::title_frame #8353 by @Its-Just-Nansextra_text_line_spacing to control vertical spacing between text lines #8040 by @rustbasicsizing_pass when reopening popup #8315 by @yayModifiers from RawInput and make it a egui::Event #8336 by @lucasmerlinclip_rect_margin #8366 by @emilkTexturesDelta #8356 by @lucasmerlinGrid being widenable but not shrinkable again #8386 by @emilkThis release drastically improves the mobile keyboard experience (when using eframe web). It also adds drag-to-open panels, window chrome theme sync and a lot of small bug fixes and improvements!
Autocomplete, autocorrect and IMEs now work correctly on iOS and android (on eframe web)!
https://github.com/user-attachments/assets/b0aa1084-0755-4e47-a0b3-0ce6890aca85
You can now reopen closed panels by dragging the handle:
https://github.com/user-attachments/assets/e02895c4-248e-4e22-9694-bdfcd9839bfd
Previously, when switching themes, the window chrome (OS titlebar) stayed in the OS theme. Now, it syncs with the app theme:
https://github.com/user-attachments/assets/6b393057-fdfc-431b-b997-744bc183a8ac
BoxedWidget: dynamically dispatched widgets #8378 by @emilkWidgetText::size #8377 by @emilkLayoutJob::clear #8376 by @emilkegui::Window::title_frame #8353 by @Its-Just-Nansextra_text_line_spacing to control vertical spacing between text lines #8040 by @rustbasicsizing_pass when reopening popup #8315 by @yayModifiers from RawInput and make it a egui::Event #8336 by @lucasmerlinclip_rect_margin #8366 by @emilkTexturesDelta #8356 by @lucasmerlinGrid being widenable but not shrinkable again #8386 by @emilkRemove everything that was marked #[deprecated] #8105 by @emilk
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
Uis to modify widget behavior based on surrounding contextThis release includes a new inspection protocol for egui. It allows reading the accesskit tree of a running app, as well
as sending events to control it. It's implemented via a new InspectionPlugin in the egui_inspection crate.
Eframe includes a new inspection feature. When enabled, you can enable inspection by launching the app with
EGUI_INSPECTION=1. This will cause the app to listen on port 5719.
The first inspection protocol consumer is egui_mcp.
It's a mcp server that allows your agent to see and use
egui apps. It can be used to have the agent use the app, reproduce bugs and verify its changes.
Install it via cargo install --git https://github.com/rerun-io/kittest_inspector egui_mcp and then add it to your
agent via claude mcp add egui egui-mcp.
There is also a plan of adding a general inspection gui using the same protocol, that can e.g. be used to step through
kittest tests frame by frame.
Here is claude using the mcp to try some of the egui demos (sped up by a lot, claude is slow):
Screen.Recording.2026-06-25.at.19.58.20.15s.movegui_inspection protocol and plugin #8234 by @lucasmerlinAs part of css like styling, we've added classes to egui. You can already
use them to e.g. modify widget behavior or styling based on surrounding context.
Add classes to the container:
ui.scope_builder(UiBuilder::new().with_class("my_container"), |ui| {
...
}); In your widget, check if we're in my_container, to e.g. change sizes or colors:
let in_container = ui.stack().iter().any(|s| s.classes.has("my_container")); Today this only works for custom widgets and ui code, but the next step will be a styling system that allows you to modify built
in widget styling based on these classes.
Classes to UiBuilder and some Widgets #7843 by @AdrienZianneIME visuals received an overhaul, they are now indicated by an underline and properly show the cursor during composition:
After-macOS-CMN-small.mp4Classes to UiBuilder and some Widgets #7843 by @AdrienZianneAtomKind::Layout, for nesting AtomLayout #8219 by @lucasmerlinAtomLayout::direction #8221 by @lucasmerlinsubpixel_binning to TextOptions and FontTweak #8072 by @emilkAtoms in Ui::small_button #8159 by @lucasmerlinegui::Window Titlebar #8154 by @lucasmerlinAsId and IdSalt #8184 by @emilkViewportBuilder::with_monitor + ViewportCommand::SetMonitor #8140 by @Le-Syl21egui::Key #8127 by @Le-Syl21AtomLayout::selectable for opt-in text selection #8224 by @akagifreeezLayoutJob::format_at_byte #8244 by @emilkatoms() helpers to get Atoms from widgets #8128 by @Nashvill375owns_ime_events on Memory #7983 by @umajhoharfrust for better kerning and ligatures #8031 by @gcaillyWindow margins and set clip_rect_margin to zero #7725 by @emilkWindow: move only by dragging title bar #8183 by @emilkPanel methods #8192 by @emilkAlphaFromCoverage to FontColorTransferFunction #8201 by @emilkDebug-formatting of Id in debug-builds #8190 by @emilkCharIndex and ByteIndex + bug fixes #8245 by @emilkGetScreenshot inspection request #8248 by @lucasmerlinFontTweak UI #8258 by @emilkFontTweak #8262 by @emilk#[deprecated] #8105 by @emilkimpl Into<f32> arguments #8194 by @emilkGrid #8170 by @lucasmerlinPanel: never overflow available width, nor max_width #8198 by @emilkegui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
wgpu::Surface lifecycle handling #8171 by @grtlrScrollArea::scroll_to_* calls when stick_to_bottom is Active #8033 by @AmmarAbouZoregui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
Context::is_pointer_over_egui and Context::egui_wants_pointer_input #8081 by @emilkTextEdit #8082 by @lucasmerlinegui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
…a &mut Ui instead of Context . In eframe we've deprecated App::update replaced it with App::ui (which provides a &mut Ui instead of a &Context ).
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
skrifaScrollAreasUi as the main entrypointThe font rendering backend was switched from ab_glyph to skrifa + vello_cpu. This enabled us support
font hinting and variations. It also paves the way for more font improvements in the future, like support for color
emojis and adding helpers for variations like RichText::bold.
Font hinting makes text more clear (look at the =):
Screen.Recording.2026-03-26.at.10.49.43.movWe now support setting variable font parameters:
Screen.Recording.2026-03-26.at.11.37.21.mp4(Unfortunately there is currently a bug with variations, meaning changing them live like this won't work in practise.
There is a draft PR to fix it, but it didn't make the release)
Ui, less Contextegui has long had a confusing overlap in responsibilities between Context and Ui.
In particular, you could add panels to either one (or both!).
In this release, we switch from having Context be the main entrypoint, and instead provide whole-app Ui.
In egui we've replaced Context::run with Context::run_ui, and changed viewports to be given a &mut Ui instead of Context.
In eframe we've deprecated App::update replaced it with App::ui (which provides a &mut Ui instead of a &Context).
In addition to this, Ui now derefs to Context, so all code like ui.ctx().input(…) can now be written ui.input(…).
This means you are much less likely to have to use naked Contexts.
Context can still be useful though, since they implement Clone and can be sent to other threads so you can call .request_repaint on them.
Context::run_ui #7736 by @emilkDeref<Target = Context> for Ui #7770 by @emilkApp::update with fn logic and fn ui #7775 by @emilkContext::style to global_style; avoid confusion w/ Ui::style #7772 by @emilkContext to avoid confusion #7773 by @emilkUi instead of Context #7779 by @emilkAs part of the above work, we have unified the panel API.
SidePanel and TopBottomPanel are deprecated, replaced by a single Panel.
Furthermore, it is now deprecated to use panels directly on Context. Use the show_inside functions instead, acting on Uis.
This unification and simplification will make it easier to maintain and improve panels going forward.
Panel to replace SidePanel and TopBottomPanel #5659 by @sharky98Panel directly on a Context #7781 by @emilkCentralPanel::show #7783 by @emilkContext::used_size and Context::available_rect #7788 by @emilkis_scrolling/is_smooth_scrolling util, checking for active scroll action #7669 by @IsseWButton::shortcut_text and right_text #7696 by @emilkScrollArea::content_margin #7722 by @emilkTypedPluginGuard and TypedPluginHandle #7780 by @apekrosViewportInfo::occluded and visible #7948 by @emilkAtom prefix/suffix support to DragValue #7949 by @lucasmerlinAtom::id, align, closure, max_size #7958 by @lucasmerlinDebugOptions::warn_if_rect_changes_id #7984 by @emilkTextEdit Atom prefix/suffix #7587 by @lucasmerlinButton::left_text #7955 by @rustbasicResponse::parent_id #8010 by @lucasmerlinContext::text_edit_focused #8014 by @emilkContext::time #8017 by @emilkUi::is_tooltip #8016 by @emilkUiStack::bg_color #8020 by @emilkegui::IdSet public #8019 by @lucasmerlinaccesskit feature and always depend on accesskit #7701 by @emilkFrameCache::get return a reference instead of cloning the cached value #7834 by @KonaeAkiraGalley::pos_from_layout_cursor pub #7864 by @dionbScrollAreas #8018 by @emilkCentralPanel::show_inside allocates space in parent #7778 by @emilkCentralPanel::show_inside_dyn to round panel_rect #7868 by @ripopovUiBuilder, to avoid wrapping passed in ids with Id::new() #7925 by @lucasmerlintruncate() and similar for os scaling other than 100% #7867 by @RndUsr123TextEdit and LayoutJob alignments #7831 by @RndUsr123horizontal_wrapping row height after using text_edit_multiline #8000 by @optozoraxVisuals::interact_cursor support in Button #7986 by @mango766egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
. as a word-splitter in text navigation #7741 by @emilkkittest: add drag-and-drop helpers #7690 by @emilkehttp to 0.6.0 #7757 by @jprochazkegui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
egui is an easy-to-use immediate mode GUI for Rust that runs on both web and native.
Try it now: https://www.egui.rs/
egui development is sponsored by Rerun, a startup building an SDK for visualizing streams of multimodal data.
Plugin::on_widget_under_pointer to support widget inspector #7652 by @juancampaResponse::total_drag_delta and PointerState::total_drag_delta #7708 by @emilkComboBox #7658 by @lucasmerlinprofiling::scope compile error when profiling using tracing backend #7646 by @PPakalnsui.response().interact(Sense::click()) being flakey #7713 by @lucasmerlinnative_pixels_per_point is set during app creation #7683 by @emilkDeprecated ImageButton and removed WidgetType::ImageButton #7483 by @Stelios-Kourlis
Highlights from this release:
egui::Plugin a improved way to create and access egui pluginsAs a step towards using parley for font rendering, @valadaptive has refactored the font loading and rendering code. A result of this (next to the font rendering code being much nicer now) is improved kerning. Notice how the c moved away from the k:
egui::Plugin traitWe've added a new trait-based plugin api, meant to replace Context::on_begin_pass and Context::on_end_pass.
This makes it a lot easier to handle state in your plugins. Instead of having to write to egui memory it can live right on your plugin struct.
The trait based api also makes easier to add new hooks that plugins can use. In addition to on_begin_pass and on_end_pass, the Plugin trait now has a input_hook and output_hook which you can use to inspect / modify the RawInput / FullOutput.
At rerun we have a ton of snapshots. Some PRs will change most of them (e.g. the one that updated egui and introduced the kerning improvements, ~500 snapshots changed!). If you really want to look at every changed snapshot it better be as efficient as possible, and the experience on github, fiddeling with the sliders, is kind of frustrating. In order to fix this, we've made kitdiff. You can use it locally via
kitdiff files . will search for .new.png and .diff.png fileskitdiff git will compare the current files to the default branch (main/master)
Or in the browser viahttps://rerun-io.github.io/kitdiff/?url=<link_to_pr_or_artifact>To install kitdiff run cargo install --git https://github.com/rerun-io/kitdiff
Here is a video showing the kerning changes in kitdiff (try it yourself):
https://github.com/user-attachments/assets/74640af1-09ba-435a-9d0c-2cbeee140c8f
egui::Mutex now has a timeout as a simple deadlock detection
egui::Mutex in some place where it's held for longer than a single frame, you should switch to the std mutex or parking_lot instead (egui mutexes are wrappers around parking lot)screen_rect is deprecated
viewport_rect and content_rect.screen_rect to content_rect, unless you are sure that you want to draw outside the safe area (which would mean your Ui may be covered by notches, system ui, etc.)Ui::take_available_space() helper function, which sets the Ui's minimum size to the available space #7573 by @IsseWUiBuilder::global_scope and UiBuilder::id #7372 by @Icekeyemath::fast_midpoint #7435 by @emilkhex_color macro const #7444 by @YgorSouzaSurrenderFocusOn option #7471 by @lucasmerlinMemory::move_focus #7476 by @darkwaterviewport::WindowLevel and dependents #7432 by @lkdmImageButton and removed WidgetType::ImageButton #7483 by @Stelios-KourlisUi #7386 by @lucasmerlindeadlock_detection feature #7497 by @lucasmerlinPlatformOutput #7523 by @emilklog feature #7583 by @emilkclippy::iter_over_hash_type lint #7421 by @emilkPreserve text format in truncated label tooltip #7514 #7535 by @lucasmerlin
TextEdit's in RTL layouts #5547 by @zakarumychFix: SubMenu should not display when ui is disabled #7428 by @ozwaldorf
SubMenu should not display when ui is disabled #7428 by @ozwaldorfUi::place, to place widgets without changing the cursor #7359 by @lucasmerlinAdd ComboBox::popup_style #7360 by @lucasmerlin
ComboBox::popup_style #7360 by @lucasmerlinPopup not closing #7383 by @lucasmerlinWidgetText::Text ignoring fallback font and overrides #7361 by @lucasmerlinoverride_text_color priority #7439 by @YgorSouzaThe old tooltip and popup apis have been ported to the new api so there should be very little breaking changes. The old menu is still around but depre…
This is a big egui release, with several exciting new features!
Let's dive in!
egui::Atom is the new, indivisible building blocks of egui (hence their name).
An Atom is an enum that can be either WidgetText, Image, or Custom.
The new AtomLayout can be used within widgets to do basic layout.
The initial implementation is as minimal as possible, doing just enough to implement what Button could do before.
There is a new IntoAtoms trait that works with tuples of Atoms. Each atom can be customized with the AtomExt trait
which works on everything that implements Into<Atom>, so e.g. RichText or Image.
So to create a Button with text and image you can now do:
let image = include_image!("my_icon.png").atom_size(Vec2::splat(12.0));
ui.button((image, "Click me!"));
Anywhere you see impl IntoAtoms you can add any number of images and text, in any order.
As of 0.32, we have ported the Button, Checkbox, RadioButton to use atoms
(meaning they support adding Atoms and are built on top of AtomLayout).
The Button implementation is not only more powerful now, but also much simpler, removing ~130 lines of layout math.
In combination with ui.read_response, custom widgets are really simple now, here is a minimal button implementation:
pub struct ALButton<'a> {
al: AtomLayout<'a>,
}
impl<'a> ALButton<'a> {
pub fn new(content: impl IntoAtoms<'a>) -> Self {
Self {
al: AtomLayout::new(content.into_atoms()).sense(Sense::click()),
}
}
}
impl<'a> Widget for ALButton<'a> {
fn ui(mut self, ui: &mut Ui) -> Response {
let Self { al } = self;
let response = ui.ctx().read_response(ui.next_auto_id());
let visuals = response.map_or(&ui.style().visuals.widgets.inactive, |response| {
ui.style().interact(&response)
});
let al = al.frame(
Frame::new()
.inner_margin(ui.style().spacing.button_padding)
.fill(visuals.bg_fill)
.stroke(visuals.bg_stroke)
.corner_radius(visuals.corner_radius),
);
al.show(ui).response
}
}
You can even use Atom::custom to add custom content to Widgets. Here is a button in a button:
https://github.com/user-attachments/assets/8c649784-dcc5-4979-85f8-e735b9cdd090
let custom_button_id = Id::new("custom_button");
let response = Button::new((
Atom::custom(custom_button_id, Vec2::splat(18.0)),
"Look at my mini button!",
))
.atom_ui(ui);
if let Some(rect) = response.rect(custom_button_id) {
ui.put(rect, Button::new("🔎").frame_when_inactive(false));
}
Currently, you need to use atom_ui to get a AtomResponse which will have the Rect to use, but in the future
this could be streamlined, e.g. by adding a AtomKind::Callback or by passing the Rects back with egui::Response.
Basing our widgets on AtomLayout also allowed us to improve Response::intrinsic_size, which will now report the
correct size even if widgets are truncated. intrinsic_size is the size that a non-wrapped, non-truncated,
non-justified version of the widget would have, and can be useful in advanced layout
calculations like egui_flex.
AtomLayout, abstracting layouting within widgets #5830 by @lucasmerlinGalley::intrinsic_size and use it in AtomLayout #7146 by @lucasmerlinIntroduces a new egui::Popup api. Checkout the new demo on https://egui.rs:
https://github.com/user-attachments/assets/74e45243-7d05-4fc3-b446-2387e1412c05
We introduced a new RectAlign helper to align a rect relative to an other rect. The Popup will by default try to find the best RectAlign based on the source widgets position (previously submenus would annoyingly overlap if at the edge of the window):
https://github.com/user-attachments/assets/0c5adb6b-8310-4e0a-b936-646bb4ec02f7
Tooltip and menu have been rewritten based on the new Popup api. They are now compatible with each other, meaning you can just show a ui.menu_button() in any Popup to get a sub menu. There are now customizable MenuButton and SubMenuButton structs, to help with customizing your menu buttons. This means menus now also support PopupCloseBehavior so you can remove your close_menu calls from your click handlers!
The old tooltip and popup apis have been ported to the new api so there should be very little breaking changes. The old menu is still around but deprecated. ui.menu_button etc now open the new menu, if you can't update to the new one immediately you can use the old buttons from the deprecated egui::menu menu.
We also introduced ui.close() which closes the nearest container. So you can now conveniently close Windows, Collapsibles, Modals and Popups from within. To use this for your own containers, call UiBuilder::closable and then check for closing within that ui via ui.should_close().
Popup and Tooltip, unifying the previous behaviours #5713 by @lucasmerlinUi::close and Response::should_close #5729 by @lucasmerlinegui::Popup #5716 by @lucasmerlinPopup API for the color picker button #7137 by @lucasmerlinMemory::keep_popup_open isn't called #5814 by @juancampaMemory::popup API in favor of new Popup API #7317 by @emilkYou can render SVG in egui with
ui.add(egui::Image::new(egui::include_image!("icon.svg"));
(Requires the use of egui_extras, with the svg feature enabled and a call to install_image_loaders).
Previously this would sometimes result in a blurry SVG, epecially if the Image was set to be dynamically scale based on the size of the Ui that contained it. Now SVG:s are always pixel-perfect, for truly scalable graphics.
Image::paint_at pixel-perfect crisp for SVG images #7078 by @emilkNon-SVG icons are also rendered better, and text sharpness has been improved, especially in light mode.
We have some silently breaking changes (code compiles fine but behavior changed) that require special care:
ui.close_menu() calls from button click handlers since they are obsoletePopupCloseBehavior: // Change this
ui.menu_button("Text", |ui| { /* Menu Content */ });
// To this:
MenuButton::new("Text").config(
MenuConfig::default().close_behavior(PopupCloseBehavior::CloseOnClickOutside),
).ui(ui, |ui| { /* Menu Content */ });
You can also change the behavior only for a single SubMenu by using SubMenuButton, but by default it should be passed to any submenus when using MenuButton.Memory::is_popup_open api now requires calls to Memory::keep_popup_openkeep_popup_open is not called.Popup api which handles this for you.keep_popup_open: if ui.memory(|mem| mem.is_popup_open(popup_id)) {
ui.memory_mut(|mem| mem.keep_popup_open(popup_id)); // <- add this line
let area_response = Area::new(popup_id).show(...)
}
Label::show_tooltip_when_elided #5710 by @brycebergerUi::allocate_new_ui in favor of Ui::scope_builder #5764 by @lucasmerlinexpand_bg to customize size of text background #5365 by @MeGaGiGaGonTextBuffer for layouter in TextEdit instead of &str #5712 by @kernelkindSlider::update_while_editing(bool) API #5978 by @mbernatScene::drag_pan_buttons option. Allows specifying which pointer buttons pan the scene by dragging #5892 by @mitchmindtreeScene::sense to customize how Scene responds to user input #5893 by @mitchmindtreeTextEdit arrow navigation to handle Unicode graphemes #5812 by @MStarhaScrollArea improvements for user configurability #5443 by @MStarhaResponse::clicked_with_open_in_background #7093 by @emilkModifiers::matches_any #7123 by @emilkContext::format_modifiers #7125 by @emilkOperatingSystem::is_mac #7122 by @emilkContext::current_pass_index #7276 by @emilkContext::cumulative_frame_nr #7278 by @emilkVisuals::text_edit_bg_color #7283 by @emilkVisuals::weak_text_alpha and weak_text_color #7285 by @emilkegui::Sides shrink_left / shrink_right #7295 by @lucasmerlinhint_text in WidgetInfo #5724 by @bircniDefault for ThemePreference #5702 by @MichaelGruppavailable_rect docs with the new reality after #4590 #5701 by @podusowskiViewport positioning #5715 by @aspiringLichSizeHint #7079 by @emilkInputOptions #7121 by @emilkButton inherits the alt_text of the Image in it, if any #7136 by @emilkTooltip slightly #7151 by @emilkui.disable() to modify opacity #7282 by @emilkBitOr and BitOrAssign for Rect #7319 by @lucasmerlinSelectableLabel #7277 by @lucasmerlinScene: make scene_rect full size on reset #5801 by @graydenshandScene: TextEdit selection when placed in a Scene #5791 by @karhuScene: Set transform layer before calling user content #5884 by @mitchmindtreeTextShape underline width #5865 by @emilkconsume_key #7134 by @lucasmerlinemoji-icon-font with fix for fullwidth latin characters #7067 by @emilkScrollArea #5286 by @gilbertoalexsantosResponse::clicked_elsewhere not returning true sometimes #5798 by @lucasmerlinDragValue expansion when editing #5809 by @MStarhaDragValue eating focus, causing focus to reset #5826 by @KonaeAkiraavailable_space #6900 by @lucasmerlinleading_space sometimes being ignored during paragraph splitting #7031 by @afishhhComboBox::from_id_source #7055 by @aelmizebend_pass is called for all loaders #7072 by @emilkdebug_assert triggered by menu/intersect_ray #7299 by @emilkRect::area to return zero for negative rectangles #7305 by @emilkWidgetText smaller and faster #6903 by @lucasmerlinFix sizing bug in TextEdit::singleline #5640 by @IaVashik
This release adds the Scene container to egui. It is a pannable, zoomable canvas that can contain Widgets and child Uis. This will make it easier to e
This release adds the Scene container to egui. It is a pannable, zoomable canvas that can contain Widgets and child Uis.
This will make it easier to e.g. implement a graph editor.
The tessellator has been updated for improved rendering quality and better performance. It will produce fewer vertices
and shapes will have less overdraw. We've also defined what CornerRadius (previously Rounding) means.
We've also added a tessellator test to the demo app, where you can play around with different values to see what's produced:
https://github.com/user-attachments/assets/adf55e3b-fb48-4df0-aaa2-150ee3163684
Check the PR for more details.
CornerRadius, Margin, Shadow size reductionIn order to pave the path for more complex and customizable styling solutions, we've reduced the size of
CornerRadius, Margin and Shadow values to i8 and u8.
StrokeKind to all your Painter::rect calls #5648StrokeKind::default was removed, since the 'normal' value depends on the context #5658
StrokeKind::Inside when drawing rectanglesStrokeKind::Middle when drawing open pathsRounding to CornerRadius #5673CornerRadius, Margin and Shadow have been updated to use i8 and u8 #5563, #5567, #5568
as i8 / as u8 or as _ if you want Rust to infer the type
f32 value is bigger than 127 it will be clamped to 127RectShape parameters changed #5565
Frame now takes the Stroke width into account for its sizing, so check all views of your app to make sure they still look right.
Read the PR for more info.egui::Scene for panning/zooming a Ui #5505 by @grtlrOutputCommand for copying text and opening URL:s #5532 by @emilkContext::copy_image #5533 by @emilkWidgetType::Image and Image::alt_text #5534 by @lucasmerlinepaint::Brush for controlling RectShape texturing #5565 by @emilknohash_hasher::IsEnabled for Id #5628 by @emilk!, {, } #5548 by @Its-Just-NansRectShape::stroke_kind to control if stroke is inside/outside/centered #5647 by @emilkFrame now includes stroke width as part of padding #5575 by @emilkRounding to CornerRadius #5673 by @emilkStrokeKind when painting rectangles with strokes #5648 by @emilkprofiling crate #5494 by @lucasmerlinArea::compare_order() #5569 by @HactarCEu8 in CornerRadius, and introduce CornerRadiusF32 #5563 by @emilkMargin using i8 to reduce its size #5567 by @emilkShadow by using i8/u8 instead of f32 #5568 by @emilkResponse and Sense #5556 by @polwelAdd Modal, a popup that blocks input to the rest of the application (#5358 by @lucasmerlin)
Modal, a popup that blocks input to the rest of the application (#5358 by @lucasmerlin)egui_kittestThis release welcomes a new crate to the family: egui_kittest.
egui_kittest is a testing framework for egui, allowing you to test both automation (simulated clicks and other events),
and also do screenshot testing (useful for regression tests).
egui_kittest is built using kittest, which is a general GUI testing framework that aims to work with any Rust GUI (not just egui!).
kittest uses the accessibility library AccessKit for automatation and to query the widget tree.
kittest and egui_kittest are written by @lucasmerlin.
Here's a quick example of how to use egui_kittest to test a checkbox:
use egui::accesskit::Toggled;
use egui_kittest::{Harness, kittest::Queryable};
fn main() {
let mut checked = false;
let app = |ui: &mut egui::Ui| {
ui.checkbox(&mut checked, "Check me!");
};
let mut harness = egui_kittest::Harness::new_ui(app);
let checkbox = harness.get_by_label("Check me!");
assert_eq!(checkbox.toggled(), Some(Toggled::False));
checkbox.click();
harness.run();
let checkbox = harness.get_by_label("Check me!");
assert_eq!(checkbox.toggled(), Some(Toggled::True));
// You can even render the ui and do image snapshot tests
#[cfg(all(feature = "wgpu", feature = "snapshot"))]
harness.wgpu_snapshot("readme_example");
}
Modal and Memory::set_modal_layer #5358 by @lucasmerlinUiBuilder::layer_id and remove layer_id from Ui::new #5195 by @emilkTextEdit #5203 by @bircniResponse::intrinsic_size for TextEdit #5266 by @lucasmerlinMultiTouchInfo #5247 by @lucasmerlinContext::add_font #5228 by @frederik-uniBox<str> for WidgetText, RichText #5309 by @dimtpapWindow::scroll_bar_visibility #5231 by @ZeenobitComboBox::close_behavior #5305 by @avalschpainter.line() #5291 by @bircniButton::image_tint_follows_text_color #5430 by @emilkContext::layer_transform_to_global & layer_transform_from_global #5465 by @emilkArc to reduce memory consumption #5276 by @StarStarJegui::util::cache to egui::cache; add FramePublisher #5426 by @emilkOrder::PanelResizeLine #5455 by @emilkprofiling crate to support more profiler backends #5150 by @teddemunnikScrollArea drag velocity when drag stopped #5175 by @valadaptiveViewportCommand::Visible #5244 by @rustbasicUi::new_child does not consider the sizing_pass field of UiBuilder #5262 by @zhatuokunWindow::default_pos does not work #5315 by @rustbasicSides did not apply the layout position correctly #5303 by @zhatuokunStyle::override_font_id in RichText #5310 by @MStarhaTextEdit inside a ScrollArea #3660 by @juancampaon_hover_text_at_pointer for transformed layers #5429 by @emilkArea outside its constrain_rect #5459 by @MScottMcBeeui.new_child should now respect disabled #5483 by @emilkRemove debug-assert triggered by with_layer_id/dnd_drag_source #5191 by @emilk
Deprecated (replaced with UiBuilder):
This release adds initial support for multi-pass layout, which is a tool to circumvent a common limitation of immediate mode.
You can use the new UiBuilder::sizing_pass (#4969) to instruct the Ui and widgets to shrink to their minimum size, then store that size.
Then call the new Context::request_discard (#5059) to discard the visual output and do another pass immediately after the current finishes.
Together, this allows more advanced layouts that is normally not possible in immediate mode.
So far this is only used by egui::Grid to hide the "first-frame jitters" that would sometimes happen before, but 3rd party libraries can also use it to do much more advanced things.
There is also a new UiBuilder for more flexible construction of Uis (#4969).
By specifying a sense for the Ui you can make it respond to clicks and drags, reading the result with the new Ui::response (#5054).
Among other things, you can use this to create buttons that contain arbitrary widgets.
0.29 also adds improve support for automatic switching between light and dark mode.
You can now set up a custom Style for both dark and light mode, and have egui follow the system preference (#4744 #4860).
There also has been several small improvements to the look of egui:
<img width="198" alt="New text selection in light mode" src="https://github.com/user-attachments/assets/bd342946-299c-44ab-bc2d-2aa8ddbca8eb"> <img width="187" alt="New text selection in dark mode" src="https://github.com/user-attachments/assets/352bed32-5150-49b9-a9f9-c7679a0d30b2">
<img width="143" alt="Old text selection in light mode" src="https://github.com/user-attachments/assets/f3cbd798-cfed-4ad4-aa3a-d7480efcfa3c"> <img width="143" alt="Old text selection in dark mode" src="https://github.com/user-attachments/assets/9925d18d-da82-4a44-8a98-ea6857ecc14f">
id_source is now called id_salt everywhere (#5025)Ui::new now takes a UiBuilder (#4969)UiBuilder):
ui.add_visible_uiui.allocate_ui_at_rectui.child_uiui.child_ui_with_id_sourceui.push_stack_infoUiBuilder for building Uis #4969 by @emilkegui::Sides for adding UI on left and right sides #5036 by @emilkUi:s: add UiBuilder::sense and Ui::response #5054 by @lucasmerlinUi::columns_const() #4764 by @v0x0gSlider::max_decimals_opt #4953 by @bircniLabel::halign #4975 by @rustbasicui.shrink_clip_rect #5068 by @emilkScrollArea::scroll_bar_rect #5070 by @emilkOptions::input_options for click-delay etc #4942 by @girtsfWidgetType::RadioGroup #5081 by @bashwith_accessibility_parent #5083 by @bashUi::with_visual_transform #5055 by @lucasmerlinSlider and DragValue compatible with NonZeroUsize etc #5105 by @emilkContext::request_discard for multi-pass layouts #5059 by @emilkFontTweak live #5125 by @emilkResponse::intrinsic_size to enable better layout in 3rd party crates #5082 by @lucasmerlinDebugOptions::show_unaligned #5165 by @emilkSlider::clamping for precise clamp control #5119 by @emilkColor32::from_rgba_unmultiplied with LUT #5088 by @YgorSouzaid_source to id_salt #5025 by @bircniId clashes by seeding auto-ids with child id #4840 by @ironpeakMargin::ui #4873 by @rustbasicscroll_to_* animations configurable #4305 by @lucasmerlinButton to correctly align contained image #4891 by @PrimmRahash re-exports #4979 by @oscargusgenerate-link-to-definition feature on docs.rs #5030 by @GuillaumeGomezMemory methods public #5046 by @bircniui.set_sizing_pass #5074 by @emilkegui::frame #5087 by @simgtlog crate instead of eprintln & remove some unwraps #5010 by @bircniEvent::Copy and Event::Cut behave as if they select the entire text when there is no selection #5115 by @rustbasicTextEdit to fix some bugs #4794 by @rustbasicstep_by #4822 by @AurevoirXavierTextEdit #4889 by @PrimmRTextEdit when clicked #4991 by @ZoxcId clash in Frame styling widget #4967 by @YgorSouzaScrollArea contents from exceeding the container size #5006 by @DouglasDwyerRawInput::take clears all events, like it says it does #5104 by @emilkDragValue range clamping #5118 by @emilkYour coding agent can read these notes before it upgrades. Set up the MCP server →