Overlays

Popover

A floating panel anchored to a trigger.

Rust
1use herogpui::components::popover::{Popover, PopoverArrow, PopoverPlacement};

Usage

Panel text and headings use a 20px line height independently of surrounding text.

Rust
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

Popover styling
StyleDescription
overlay colors + text_size(px(14.)) + container_radius + overlay_shadowSurface 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_focusSixteen-pixel inset and a programmatic dialog focus scope.
FontWeight::MEDIUMHeading uses the 500 weight.
Motion::POPOVER_IN + entering_zoomDuration, curve, fade and zoom match; transform origin and placement slide are absent.
Motion::LIST_OUT + exitingExit duration, curve, fade and zoom match.
PopoverArrow svg child + PopoverSide::arrow_rotation + arrow_originSize, 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_pointerThe wrapper is interactive and the child owns focus/disabled visuals, but inline-block and these transitions are not reproduced.
HEROGPUI_REDUCE_MOTION + animation helpersThe panel renders immediately without geometric animation.

API reference

Builders

Popover builders
BuilderTypeDefaultDescription
new(trigger)triggerCompound trigger and content children; takes the trigger positionally and panel children through ParentElement.
is_open(bool)boolControlled open state.
default_open(bool)boolfalseInitial uncontrolled open state.
on_open_change(callback)Fn(isOpen: bool) -> ()Reports trigger, Escape, outside-press and explicit close changes.
placement(PopoverPlacement)PopoverPlacementPopoverPlacement::BottomEight cardinal/start/end placements are available; full placement union is not represented.
offset(Pixels)Pixels8Distance between trigger and panel.
should_flip(bool)booltrueChanges to the opposite orientation when the preferred side would overflow and the opposite side fits better.
new() + ParentElement childrenAnyElementThe 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

Popover parts
PartDescription
PopoverControlled or uncontrolled owner of open state, focus scope and dismissal lifecycle.
PopoverInteractive wrapper around the positional trigger child; not separately replaceable or styled.
PopoverPlacement-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.
PopoverArrowComposed 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.
PopoverDialog focus scope and 16px content inset are built into the monolithic panel.
PopoverThe title builder draws the medium-weight heading, but Heading is not an independently composable part.

States

Popover states
BuilderStateDescription
overlay_scope Open + entering_zoom(Motion::POPOVER_IN)Entering150ms Smooth fade and zoom from 90%; v3's placement-specific 4px translation is not reproduced.
overlay_scope Exiting + exiting(Motion::LIST_OUT)ExitingRemains mounted for the 100ms Smooth fade and zoom to 95%.
PopoverPositioner + PlacementPlacementEight placements align to the trigger and shouldFlip resolves the fitting orientation; placement attributes and the wider union are absent.
trigger child focus treatmentFocus visibleKeyboard focus and its visible ring remain owned by the caller-provided trigger control.