Popover
A floating panel anchored to a trigger.
1use herogpui::components::popover::{Popover, PopoverArrow, PopoverPlacement};Usage
Panel text and headings use a 20px line height independently of surrounding text.
1use herogpui::prelude::{Button, Popover, PopoverArrow, PopoverPlacement, Variant};
2use gpui::prelude::*;
3use gpui::px;
4
5overlay_min_h(usage_slot, is_open, 160.)
6 .child(
7 Popover::new(
8 gpui::div()
9 .pr(px(96.))
10 .child(
11 Button::new("popover-trigger")
12 .label("Open popover")
13 .variant(Variant::Secondary),
14 ),
15 )
16 .is_open(is_open)
17 .title("Quick note")
18 .placement(PopoverPlacement::Bottom)
19 .child(gpui::div().child("Popovers are anchored to their trigger."))
20 .on_open_change(bool_cb(cx.listener(|this, open: &bool, _, cx| {
21 set_popover_open(
22 &mut this.popover_open,
23 &mut this.demo_flags,
24 "po-usage",
25 *open,
26 );
27 cx.notify();
28 }))),
29 )Live HeroGPUI compiled to WebAssembly. Select any example without loading another WASM instance.
Anatomy
Rust types
PopoverPopoverArrow
Popover is assembled from these builders. The API reference lists each one.
Customization
Appearance builders and theme tokens Popover uses.
Styling
| Style | Description |
|---|---|
overlay colors + text_size(px(14.)) + container_radius + overlay_shadow | Surface colour, 14/20px text, capped radius and overlay shadow match; the monolithic panel combines root and dialog padding. |
px(px(16.)) + py(px(16.)) + panel_focus | Sixteen-pixel inset and a programmatic dialog focus scope. |
FontWeight::MEDIUM | Heading uses the 500 weight. |
Motion::POPOVER_IN + entering_zoom | Duration, curve, fade and zoom match; transform origin and placement slide are absent. |
Motion::LIST_OUT + exiting | Exit duration, curve, fade and zoom match. |
PopoverArrow svg child + PopoverSide::arrow_rotation + arrow_origin | Size, built-in curve, fill and flip-aware rotation match. Upstream applies the same placement rotation to a custom child through its data-slot selector, which GPUI 0.2.2 cannot do for an arbitrary div element; places a custom child unrotated. |
relative flex wrapper + cursor_pointer | The wrapper is interactive and the child owns focus/disabled visuals, but inline-block and these transitions are not reproduced. |
HEROGPUI_REDUCE_MOTION + animation helpers | The panel renders immediately without geometric animation. |
API reference
Builders
| Builder | Type | Default | Description |
|---|---|---|---|
new( | trigger | — | Compound trigger and content children; takes the trigger positionally and panel children through ParentElement. |
is_open( | bool | — | Controlled open state. |
default_open( | bool | false | Initial uncontrolled open state. |
on_open_change( | Fn( | — | Reports trigger, Escape, outside-press and explicit close changes. |
placement( | PopoverPlacement | PopoverPlacement:: | Eight cardinal/start/end placements are available; full placement union is not represented. |
offset( | Pixels | 8 | Distance between trigger and panel. |
should_flip( | bool | true | Changes to the opposite orientation when the preferred side would overflow and the opposite side fits better. |
new( | AnyElement | — | The built-in 12px curve renders by default and a custom element composes through ParentElement at the resolved arrow position. Upstream stamps the single child with data-slot=popover-overlay-arrow so the.popover placement CSS rotates it too; GPUI 0.2.2 transforms only svg elements, so a custom child takes the position without the rotation. |
Parts
| Part | Description |
|---|---|
Popover | Controlled or uncontrolled owner of open state, focus scope and dismissal lifecycle. |
Popover | Interactive wrapper around the positional trigger child; not separately replaceable or styled. |
Popover | Placement-aware surface with true orientation flipping and pinned motion; GPUI 0.2.2 cannot nest deferred portal draws, so the panel remains in its ancestor clipping context. |
PopoverArrow | Composed part drawing the built-in 12px curved arrow centred on the trigger and rotated for the resolved side, or a caller-supplied child element at the resolved position. Upstream rotates the single custom child through its data-slot placement CSS; GPUI 0.2.2's svg-only transformation cannot reproduce that for an arbitrary element. |
Popover | Dialog focus scope and 16px content inset are built into the monolithic panel. |
Popover | The title builder draws the medium-weight heading, but Heading is not an independently composable part. |
States
| Builder | State | Description |
|---|---|---|
overlay_scope Open + entering_zoom(Motion::POPOVER_IN) | Entering | 150ms Smooth fade and zoom from 90%; v3's placement-specific 4px translation is not reproduced. |
overlay_scope Exiting + exiting(Motion::LIST_OUT) | Exiting | Remains mounted for the 100ms Smooth fade and zoom to 95%. |
PopoverPositioner + Placement | Placement | Eight placements align to the trigger and shouldFlip resolves the fitting orientation; placement attributes and the wider union are absent. |
trigger child focus treatment | Focus visible | Keyboard focus and its visible ring remain owned by the caller-provided trigger control. |