Tooltip
Contextual information shown on hover or focus.
use herogpui::components::tooltip::Tooltip;Tooltip on docs.rsSource at v0.14.0
Usage
Showing With Arrow, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.
An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Tooltip, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![
Tooltip::new("With an arrow")
.show_arrow(true)
// `offset` is the gap between trigger and panel.
.offset(px(10.))
.radius(px(4.))
.child(
Button::new("tooltip-arrow-on")
.label("Arrow")
.variant(Variant::Secondary),
)
.into_any_element(),
Tooltip::new("Without one")
.show_arrow(false)
.child(
Button::new("tooltip-arrow-off")
.label("No arrow")
.variant(Variant::Secondary),
)
.into_any_element(),
])`body` draws the tip yourself, in place of the measured single line. The string handed to `Tooltip::new` is still required: it stays the tip's accessible name, so a rich tip cannot ship unnamed. An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Button, Tooltip, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, px};
use herogpui::gpui;
Tooltip::new("name is the identifier, kind is the token class, scope is where it resolves")
.delay(0)
.body(|_, cx| {
let muted = cx.colors().muted;
let row = |name: &str, meaning: &str| {
gpui::div()
.flex()
.gap(px(8.))
.child(gpui::div().w(px(44.)).child(name.to_owned()))
.child(
gpui::div()
.text_color(muted)
.child(meaning.to_owned()),
)
};
gpui::div()
.flex()
.flex_col()
.gap(px(2.))
.child(row("name", "the identifier"))
.child(row("kind", "the token class"))
.child(row("scope", "where it resolves"))
.into_any_element()
})
.child(
Button::new("tooltip-rich")
.label("Naming tokens")
.variant(Variant::Secondary),
)Also calls row (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ActiveTheme, Avatar, Button, Chip, ChipLabel, ChipVariant, Color, Size, Tooltip, TooltipTrigger, Variant, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![
Tooltip::new("Jane Doe")
.delay(0)
.show_arrow(true)
.child(Avatar::new("tooltip-avatar").name("Jane Doe").size(Size::Sm))
.into_any_element(),
Tooltip::new("Verified account")
.delay(0)
.child(
Chip::new()
.color(Color::Success)
.variant(ChipVariant::Soft)
.child(ChipLabel::new().child("Verified")),
)
.into_any_element(),
Tooltip::new("What is this?")
.delay(0)
.child(gpui::svg()
.size(px(16.))
.path(icons::SEARCH)
.text_color(cx.colors().foreground)
.into_any_element())
.into_any_element(),
Tooltip::new("Tab to me")
.delay(0)
// `trigger="focus"`: the pointer does nothing and
// keyboard focus is what opens it.
.trigger(TooltipTrigger::Focus)
.child(
Button::new("tooltip-focus-only")
.label("Focus only")
.variant(Variant::Secondary),
)
.into_any_element(),
])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Tooltip, TooltipPlacement, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![
Tooltip::new("Above the trigger")
.placement(TooltipPlacement::Top)
.child(
Button::new("tooltip-top")
.label("Top")
.variant(Variant::Secondary),
)
.into_any_element(),
Tooltip::new("Below the trigger")
.placement(TooltipPlacement::Bottom)
.child(
Button::new("tooltip-bottom")
.label("Bottom")
.variant(Variant::Secondary),
)
.into_any_element(),
])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Tooltip, TooltipPlacement, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(TooltipPlacement::ALL
.iter()
.map(|p| {
Tooltip::new(p.label())
.placement(*p)
.show_arrow(true)
.child(
Button::new(format!("tooltip-{}", p.label()))
.label(p.label())
.variant(Variant::Secondary)
.into_any_element(),
)
.into_any_element()
}))An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Tooltip, Variant};
use herogpui::gpui::prelude::*;
Tooltip::new(
"https://example.com/a-really-long-unbroken-token-that-must-wrap-inside-the-tooltip",
)
.delay(0)
.show_arrow(true)
.child(
Button::new("tooltip-long-content-trigger")
.label("Long token")
.variant(Variant::Secondary),
)An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Tooltip};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![
Tooltip::new("Opens at once")
.delay(0)
.child(
Button::new("tooltip-instant")
.label("No delay")
.into_any_element(),
)
.into_any_element(),
Tooltip::new("Waits half a second")
.delay(500)
.close_delay(0)
.child(Button::new("tooltip-slow").label("500ms").into_any_element())
.into_any_element(),
])HeroGPUI extension, not a example: `HoverCard` previews rich content while its trigger is hovered (after `open_delay`, 700ms by default) or focused from the keyboard (at once). Moving the pointer onto the card keeps it open so its content can be read and pressed; leaving both starts `close_delay`, and Escape or a press outside closes it. The card is a labelled group, not a tooltip. An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Avatar, Button, HoverCard, Link, Tooltip, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![
HoverCard::new("tooltip-hover-card-profile")
.label("Jane Doe's profile")
.content(|_, cx| {
let muted = cx.colors().muted;
gpui::div()
.flex()
.gap(px(12.))
.child(Avatar::new("tooltip-hover-card-avatar").name("Jane Doe"))
.child(
gpui::div()
.flex()
.flex_col()
.gap(px(4.))
.child(
gpui::div()
.font_weight(gpui::FontWeight::MEDIUM)
.child("Jane Doe"),
)
.child(
gpui::div()
.text_color(muted)
.child("Design engineer. Builds the component library and its docs."),
)
.child(
Link::new("tooltip-hover-card-link")
.label("View profile"),
),
)
.into_any_element()
})
.child(
Button::new("tooltip-hover-card-trigger")
.label("@jane")
.variant(Variant::Tertiary),
)
.into_any_element(),
])Helpers used by these examples
Plain functions over the public API, defined once here and copied with each example that calls them.
fn row(children: Vec<AnyElement>) -> AnyElement {
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(children)
.into_any_element()
}Anatomy
Rust types
Tooltip is assembled from these builders. The API reference lists each one.
Customization
Shared appearance belongs on ThemeBuilder::components and .recipe("name"). Typed builders change how Tooltip looks at one call site. Every builder also carries sx for placement, width and flex: it takes GPUI's own styling methods and refines them over the component's root after the theme, so an instance override wins. Behaviour builders live in the API reference below.
Styling
| Method | Values | Description |
|---|---|---|
placement(TooltipPlacement) | Placement | The full 22-value union renders through the shared placement vocabulary: physical and aligned spellings plus the logical start/end aliases, which share their left/right side's pixels because GPUI has no RTL layout mode. |
// The one slot for caller-owned low-level styling: GPUI's
// styling methods, refined over the root element last.
.sx(|el| {
el.bg(gpui::rgba(0xffa500ff)) // background
.text_color(gpui::rgba(0x000000ff)) // text
.w(gpui::px(13.)) // size
.h(gpui::px(12.))
})API reference
Against HeroUI v3.2.6: 13 entries ported, 6 partial, 6 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.
Builders
| Builder | Values | Default | Description |
|---|---|---|---|
new(Partial | AnyElement | โ | Trigger and content composition; takes tip text positionally and trigger children through ParentElement. |
delay( | number | 1500 | The pinned docs table says 700; v3.2.6 runtime resolves 1500 from --tooltip-delay, matching pinned 's default. |
close_delay( | number | 500 | The pinned docs table says zero; v3.2.6 runtime resolves 500 from --tooltip-close-delay, matching pinned 's default. |
trigger( | TooltipTrigger:: | TooltipTrigger:: | Hover also answers keyboard focus; Focus ignores pointer hover. |
is_disabled( | true | | false | Suppresses the tooltip while leaving its trigger content rendered. |
should_skip_animation( | true | | false | Shows and hides without the tooltip animation wrapper. |
new(Partial | AnyElement | โ | Tooltip body content; accepts text rather than arbitrary elements. |
show_arrow( | true | | false | Draws the built-in curved arrow. |
offset( | number | 3 ( | Distance from the trigger, including v3's arrow-aware default. |
placement( | Placement | TooltipPlacement:: | The full 22-value union renders through the shared placement vocabulary: physical and aligned spellings plus the logical start/end aliases, which share their left/right side's pixels because GPUI has no RTL layout mode. |
ParentElement::Partial | AnyElement | โ | Trigger content is composed as the Tooltip's child, but does not expose a separately replaceable trigger part. |
Not ported6 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
Tooltip.Content.className | CSS class override. |
Tooltip.Content.render | Render override. |
Tooltip.Trigger.className | CSS class override for the trigger wrapper. |
Tooltip.Arrow.children | Custom arrow content; exposes only the built-in arrow switch. |
Tooltip.Arrow.className | CSS class override for the arrow wrapper. |
Tooltip.Arrow.render | Arrow render override. |
Parts
| Part | Description |
|---|---|
Tooltip | State owner for delay, trigger mode and open lifecycle. |
TooltipPartial | Hover/focus wrapper around caller-provided trigger content; GPUI has no inline-block display mode. |
Tooltip | Floating overlay surface containing the tooltip text. |
TooltipPartial | Optional 12px curved arrow; custom arrow content and the separate 40% border stroke are unavailable. |
States
| State | Builder | Description |
|---|---|---|
Global sequence | TooltipManager | Only one tooltip stays open; the first hover waits for delay, later hovers during max(500ms, closeDelay) cooldown open immediately, and the sequence becomes cold again after cooldown. |
EnteringPartial | overlay_phase Entering | 150ms Smooth fade and zoom from 90% with the 4px translation for the tooltip side; GPUI still has no transform-origin primitive. |
Exiting | overlay_phase Exiting | 100ms Smooth fade and zoom to 95%. |
Placement | TooltipPlacement match | The 22-value union keeps the panel and arrow on the matching trigger edge: side-plus-alignment spellings pin their named edge, and the logical start/end aliases share their physical left/right spelling without RTL. |