Rust egui Tutorial #18: Tooltips — Add Hover Hints to Any Widget
Video: Rust egui Tutorial #18: Tooltips — Add Hover Hints to Any Widget by Taught by Celeste AI - AI Coding Coach
.on_hover_text("...")and.on_hover_ui(|ui| ...)— attach explanatory hints to any widget by chaining one call onto itsResponse.
Tooltips are a small, almost-invisible UX detail that matters a lot. Hover any button in a real desktop app and you usually get a one-line explanation. egui's tooltip API is one method on Response — chain it after any widget and you get a tooltip.
What we are building
A demo with tooltips on every interactive element. Buttons in a top toolbar, each with a different style of tooltip — plain text, rich UI, follows-the-cursor. Some labels with attached tooltips. A status indicator whose tooltip shows context computed from the app state.
.on_hover_text
if ui.button("Count").on_hover_text("Click to increment the counter").clicked() {
self.count += 1;
}
The basic case. .on_hover_text("...") takes a string slice and attaches it as a simple text tooltip. The method returns the same Response, so you can chain .clicked() afterwards.
This is the right tooltip 80% of the time. Short label that tells the user what the widget does. Discoverable without being intrusive.
The chain in this line: ui.button("Count") returns a Response. .on_hover_text(...) returns the same Response (with the tooltip attached). .clicked() is the final method check. All in one expression.
.on_hover_ui
if ui
.button("Reset")
.on_hover_ui(|ui| {
ui.heading("Reset");
ui.label("Sets the counter back to zero.");
ui.label("Also clears the name field.");
})
.clicked()
{
self.count = 0;
self.name.clear();
}
When a one-liner isn't enough, .on_hover_ui(|ui| { ... }) accepts a closure. The closure receives a Ui and you add widgets — labels, headings, anything that fits in a tooltip. The result is a tooltip with multiple lines, formatting, even icons or images if you want.
Use .on_hover_ui when:
- You need multi-line explanations.
- You want a heading inside the tooltip.
- The tooltip's content depends on app state.
- You want to include a small icon or styled text.
For most buttons, on_hover_text is enough. on_hover_ui is for the few important controls that deserve more.
.on_hover_ui_at_pointer
ui.label("Hover over each item below:")
.on_hover_ui_at_pointer(|ui| {
ui.label("This tooltip follows your cursor!");
});
Variant: the tooltip appears at the cursor position rather than next to the widget. Useful for hover-sensitive content where the user is exploring a region — like hovering over points on a chart or cells in a table. The default behaviour anchors the tooltip to the widget; this method anchors it to the pointer.
Dynamic tooltip content
ui.label(status)
.on_hover_ui(|ui| {
ui.strong("Status Info");
ui.label(format!("Name length: {} characters", self.name.len()));
ui.label(format!("Counter value: {}", self.count));
});
The closure can read self (because it captures by reference). The tooltip's content is computed every time the user hovers, so it reflects the current state.
This is great for "explain this state" tooltips. A status indicator that shows the latest sync time. A user-name display whose tooltip shows the email. A row count whose tooltip shows filter details.
Combining tooltip styles
Most buttons in this episode get a tooltip — and the styles vary:
ui.button("Count").on_hover_text("Click to increment the counter")
ui.button("Reset").on_hover_ui(|ui| { /* multiline */ })
ui.button(theme_label).on_hover_text("Toggle between dark and light mode")
ui.text_edit_singleline(&mut self.name).on_hover_text("Type your name here")
ui.label("Status:").on_hover_text("Shows the current app state")
ui.label(status).on_hover_ui(|ui| { /* dynamic */ })
The pattern is the same across all of them: chain on_hover_* after the widget call. egui handles the timing (tooltips appear after a short hover delay), positioning (next to the widget by default), and dismissal (vanish on mouse-out).
Theme switch as bonus
if self.dark_mode {
ctx.set_visuals(egui::Visuals::dark());
} else {
ctx.set_visuals(egui::Visuals::light());
}
ctx.set_visuals swaps the entire egui colour scheme. Visuals::dark() and Visuals::light() are the two presets. For custom themes, build a Visuals from scratch or modify the presets — we will explore this in Episode 26.
Running it
cargo run. The window opens with three buttons in a toolbar. Hover any of them — a tooltip appears after a short delay. Notice "Reset" has a multi-line tooltip; "Count" and "Dark" have one-liners.
Click "Count" a few times. Hover the count display in the central panel — tooltip explains it. Type a name in the field. Hover the status label — the tooltip shows your name's length plus the current count. Toggle the theme button — the whole UI switches between dark and light.
Tooltip best practices
- Always tooltip non-obvious buttons. Especially icon-only buttons, where the icon alone is ambiguous.
- Keep tooltips short. A sentence at most. Multi-paragraph tooltips are not read.
- Do not duplicate the label. A button labeled "Save" with tooltip "Save" is noise. Tooltip should add information: "Save (Cmd+S)" or "Save the current document to disk."
- Avoid tooltips on text inputs unless they explain format. "Type your name here" is patronising; "Format: first.last@company.com" is useful.
- Use rich tooltips sparingly. Multi-line UI tooltips draw attention. Reserve them for genuinely complex widgets.
Common mistakes
Chaining on_hover_text after clicked. clicked() returns bool, not Response. The chain has to go: widget → on_hover → clicked. Reorder if you got it wrong.
Tooltips that change while the user is reading them. If the underlying state changes mid-hover (e.g. an animated counter), the tooltip can flicker. Either cache the state or use on_hover_text instead of on_hover_ui.
Forgetting to escape variables in format!. { is a format placeholder; to display a literal {, use {{.
Tooltips with the same content as the visible label. Useless. Either remove them or replace with something informative.
What's next
Next episode: custom painting. Draw shapes, paths, and gradients with egui's Painter API. Useful for charts, sparklines, dashboards, and custom indicators.
Recap
.on_hover_text(text) for one-line tooltips. .on_hover_ui(|ui| { ... }) for rich, multi-widget tooltips. .on_hover_ui_at_pointer(|ui| { ... }) for cursor-following ones. Chain after any widget call before .clicked(). Tooltip content can read app state freely.
Next episode: custom painting. See you in the next one.