Skip to content
Glint UI

Popover

A click-opened floating surface for rich interactive content, anchored to a trigger and dismissed on click-outside or Escape.

Usage

import { Button } from "@glint/components/button.slint";
import { Popover } from "@glint/components/popover.slint";
export component AppWindow inherits Window {
VerticalLayout {
alignment: center;
trigger := Button {
text: "Open Popover";
haspopup: true;
clicked => { pop.show(); }
}
}
// Zero-size anchor: place it with x/y relative to your trigger.
pop := Popover {
x: trigger.x;
y: trigger.y + trigger.height + 6px;
content-width: 280px;
VerticalLayout {
// your popup content
}
}
}

Popover is a lightweight, click-opened floating surface built on Glint’s Panel primitive. Its @children slot holds whatever content you provide, while Glint manages the border, shadow, background styling, and native dismissable-layer behavior.

The Popover element acts as a zero-size anchor at its specified x/y coordinates. Opening it calls show() and closing it calls close(), mirroring Slint’s PopupWindow API.

Examples

Custom width

content-width sets the horizontal size of the floating surface (defaulting to 260px). The surface’s height automatically expands to fit its child content.

Surface placement and alignment with Panel

When you need placement vocabulary anchored to a trigger’s geometry, compose with the underlying Panel primitive directly. Setting zone-width and zone-height to match the trigger allows surface-side (PanelSide.top, PanelSide.bottom, PanelSide.left, PanelSide.right) and surface-align (PanelAlign.start, PanelAlign.center, PanelAlign.end) to position the surface automatically.

Focusing popup content with PanelFocusScope

Slint does not automatically route keyboard focus across PopupWindow boundaries. Wrapping interactive popup content in PanelFocusScope immediately hands focus to the popup when it appears so keyboard users can interact with its contents right away.

API Reference

Properties

PropertyTypeDefaultDescription
content-widthin length260pxWidth of the surface; its height follows the content.
surface-labelin stringno defaultWhat the open surface announces itself as. Nothing is drawn from either — shadcn's PopoverTitle / PopoverDescription are content, and content is the consumer's (ADR-0006) — but without them an open popover is an unnamed rectangle to assistive technology. They are named for the *surface* rather than being title / description, and not only to stay clear of the string-only pair ADR-0006 removed: the anchor and the surface are two different things here, and only the second of them is what opens. accessible-label on the Popover element itself would describe the zero-size anchor, which is outside the PopupWindow and never on screen.
surface-descriptionin stringno default
is-openout boolno defaultTrue while the surface is on screen; mirrors PopupWindow.is-open.

Functions

FunctionDescription
show()Opens the surface. Mirrors PopupWindow.show().
close()Closes the surface. Mirrors PopupWindow.close().

Panel

The underlying floating surface primitive that handles PopupWindow anchoring, geometry, and dismissable layers.

Properties

PropertyTypeDefaultDescription
content-widthin length260pxWidth of the floating surface; its height follows the content.
content-paddingin lengthTokens.spacing-lgInset between the surface's border and the slotted content. The spacing-lg default is the Popover chrome; content that draws its own inset (TimeGrid inside TimePicker) sets 0 to avoid double padding.
max-content-heightin length0pxCeiling on the whole surface, chrome included; 0 (the default) lets it grow with its content. The inset is the surface's own, so a rider capping itself no longer has to reach into content-padding to undo it — changing the panel's default inset used to silently change that one rider's height and nothing else's. A list whose rows are all one height wants min(rows, n * row-height) on its own scrolling surface instead — Select and Command cap themselves in rows, which is the unit a reader actually means.
is-openout boolno defaultTrue while the surface is on screen; mirrors PopupWindow.is-open.
zone-widthin length0pxA popup may claim more area than its surface occupies. An open PopupWindow takes every pointer event in the window wherever it sits, so a surface that has to react to the pointer resting on its *trigger* can only do it by covering that trigger — Tooltip reached the same conclusion from the other side (ADR-0007). The zone is the *trigger's rectangle*, in the anchor's own coordinates; the Panel unions it with wherever the surface lands and makes the popup that big. Zero width means no zone, and the popup is exactly the surface at the anchor — which is every other rider, unchanged.
zone-heightin length0px
surface-sidein PanelSidePanelSide.bottomWhere the surface sits against that rectangle. This is the one placement vocabulary in the library that Glint resolves rather than the consumer, and it is confined to zone riders on purpose: placing a surface *above* its trigger means subtracting a height only the Panel can measure, because a PopupWindow's insides may only be read from inside it. Without a zone there is no trigger rectangle to place against, and geometry stays the consumer's x/y (ADR-0006) — which is why Popover has no side and HoverCard does.
surface-alignin PanelAlignPanelAlign.start
surface-gapin length0pxClearance between the trigger's edge and the surface.
zone-hoveredout boolno defaultTrue while the pointer is inside the zone but not over the surface, which is what a zone exists to know. The surface sits above the zone's own TouchArea, so content inside it keeps its pointer events and reports its own hover; a rider ORs the two.
surface-labelin stringno defaultThe name and description the open surface announces itself with. They cannot come from the rider's own element: that is a zero-size anchor *outside* the PopupWindow, so an accessible-label on it would describe the anchor rather than the surface that opened. A rider forwards its own properties here instead — Popover does.
surface-descriptionin stringno default

Callbacks

CallbackDescription
zone-clicked()Fired when a click lands on the zone but outside the surface. The click cannot reach whatever is underneath — that is the price of covering it — so a rider should take the surface down and let the next click through, the way Tooltip does.

Functions

FunctionDescription
show()Shows the surface. Mirrors PopupWindow.show().
close()Closes the surface. Mirrors PopupWindow.close().

Enums

EnumValues
PanelSidetop, right, bottom, left
PanelAlignstart, center, end

PanelFocusScope

A FocusScope that immediately takes keyboard focus when the surface appears.

PanelFocusScope publishes no properties, callbacks or functions of its own. What a call site can set on it is the Slint FocusScope it inherits.

Accessibility

  • Surface landmark. The open popover surface exposes an accessible region landmark named by surface-label and described by surface-description.
  • Dismissable layers. Escape and clicks outside the surface dismiss the popover. With nested or stacked layers, Escape closes only the topmost layer.
  • Focus restoration. Dismissing the popover automatically restores keyboard focus to the trigger element that held focus before show() was called.
  • The trigger. Controls that toggle a popover should declare haspopup: true on the trigger button.