Popover
Overview
Section titled “Overview”Popover is a lookless ContentControl whose Content is the trigger and whose PopoverContent is
the floating panel; the web family’s separate Trigger/Anchor/Positioner parts collapse onto this
one root control. It positions its panel via the shared NaviusAnchoredPopup (a native Popup
driven by PlacementMath) and pushes onto the shared OverlayStack on open, registering the popup
content as an input root so Escape and outside-press dismissal work from inside the Popup’s own
HwndSource.
xmlns:navius="clr-namespace:Navius.Wpf.Primitives.Controls;assembly=Navius.Wpf.Primitives"
<navius:NaviusPopover Title="Share" Side="Bottom"> <navius:NaviusButton Content="Share" /> <navius:NaviusPopover.PopoverContent> <StackPanel> <TextBlock Text="Copy the link below." /> <navius:NaviusButton Content="Close" Command="{x:Static navius:NaviusPopover.CloseCommand}" /> </StackPanel> </navius:NaviusPopover.PopoverContent></navius:NaviusPopover>No NaviusOverlayLayer is required: Popover hosts its panel through a native Popup
(NaviusAnchoredPopup), pushing directly onto OverlayStack.GetFor(window) rather than through the
layer-hosted mechanism Dialog/AlertDialog/Drawer use.
Properties
Section titled “Properties”| Property | Type | Default | From | Description |
|---|---|---|---|---|
PopoverContent |
object? |
null |
NaviusPopover |
Content of the popup panel. |
Title |
object? |
null |
NaviusPopover |
Labels the popup; mirrored onto AutomationProperties.Name on the popup content when set. |
Description |
object? |
null |
NaviusPopover |
Describes the popup; mirrored onto AutomationProperties.HelpText on the popup content when set. |
Side |
PlacementSide |
Bottom |
NaviusPopover |
Which side of the trigger the popup is placed against. |
Align |
PlacementAlign |
Center |
NaviusPopover |
Cross-axis alignment relative to the trigger. |
SideOffset |
double |
6 |
NaviusPopover |
Gap, in DIPs, between the trigger and the popup along Side. |
AlignOffset |
double |
0 |
NaviusPopover |
Offset, in DIPs, along the cross axis. |
Modal |
bool |
false |
NaviusPopover |
Forwarded to OverlayOptions.Modal (available via OverlaySession.IsModal, e.g. to decide whether to render a backdrop). Does not gate focus-trap behavior in this port: see Web deltas. |
IsOpen |
bool |
false |
NaviusPopover |
Open state. Two-way bindable by default. |
Content |
object |
- |
ContentControl |
The trigger. |
Commands
Section titled “Commands”| Command | Description |
|---|---|
NaviusPopover.CloseCommand |
Bind any element inside PopoverContent to close the popover, mirroring the web’s NaviusPopoverClose part. Its CommandBinding is added directly to the popup content root in OnApplyTemplate, not class-registered, because the popup content lives inside a Popup’s own disconnected visual root. |
Keyboard interactions
Section titled “Keyboard interactions”| Key | Behavior |
|---|---|
Escape |
Closes the popover (CloseOnEscape fixed true when the session is pushed). |
Tab / Shift + Tab |
Cycles focus within the popup content. TrapFocus is pushed true unconditionally (see Web deltas), so this always applies regardless of Modal. |
An outside press also closes the popover (CloseOnOutsideClick fixed true when the session is
pushed); not a keyboard interaction, but shares the same dismiss-routing path.
UIA mechanism
Section titled “UIA mechanism”NaviusPopover does not override OnCreateAutomationPeer, so it ships no custom automation peer
or role="dialog"-equivalent mapping. Automation identity is approximated entirely through
AutomationProperties.AutomationId set on the trigger and popup-content template parts, plus
Name/HelpText mirrored from Title/Description directly onto the popup content
(ApplyAutomationLabels()), rather than through a role- or pattern-bearing peer. The unit suite
(PopoverTests.cs) exercises the CloseCommand binding, the always-true focus trap, and the
absence of any exposed cancelable dismiss callback.
Web deltas
Section titled “Web deltas”- Trigger, Anchor, and Positioner collapse onto the root control:
Contentis the trigger,PopoverContent/Side/Align/SideOffset/AlignOffsetare the positioner. There is no separateNaviusPopoverAnchorpart; the trigger is always the position reference. Modalvs. focus trap: the web only engages a focus trap whenModalis true.Navius.Wpf.Primitives.Overlays.OverlayOptions.TrapFocusconflates “move focus into the popup on open” and “cycle Tab within it” into one flag with no way to request the first without the second, so this port always pushesTrapFocus = trueregardless ofModal;Modalis still tracked and forwarded toOverlayOptions.Modal, but does not currently gate focus behavior differently. Splitting that flag was out of scope for the Overlays substrate.- No custom
AutomationPeer:aria-haspopup/aria-expanded/role="dialog"are approximated only viaAutomationProperties.AutomationId, not a role/pattern-bearing peer. - No arrow glyph in the default template:
NaviusAnchoredPopupsurfacesArrowSize/ArrowOffsetX/ArrowOffsetY(added in a later wave), butNaviusPopoverdoes not currently consume them. - No cancelable dismiss callbacks are exposed as public events (
OnEscapeKeyDown,OnPointerDownOutside, etc. have noNaviusPopover-level equivalent); dismissal always proceeds once requested. - Known residual (M6 audit): clicking the trigger to close an open popover can close-then-reopen.
The trigger lives in the window’s own
HwndSourcewhile the session’s input root is the popup content in thePopup’s separateHwndSource, so a mouse-down on the trigger is “outside” the session and closes it on mouse-down, then the trigger’s ownClick(mouse-up) togglesIsOpenback totrue. Confirming this needs real mouse routing (the existing test simulates the click handler directly); any fix touches outside-press routing in the sharedOverlayStack, so it is left for the Overlays owner.
Captures
Section titled “Captures”The Popover Gallery page rendered at the pinned commit, in each theme.


