Skip to content

Popover ​

A popover is a small floating panel that opens next to the element that triggered it. It is typically used for overflow menus and short contextual content.

IonPopover is the declarative component. IonPopoverController creates a popover from code. See Overlays for where overlays render, what has to be in place, and how dismiss results work.

Basic usage ​

Put the content between the tags; it goes into a box 250 px wide on md and 200 px on ios, at most 90% of the screen height, scrolling if needed. To anchor the popover to the button that opened it, pass the button's click event as Event. IonButton's OnClick handler can take a Miko.Events.MouseEventArgs. Without an Event, the popover is centered on the screen. Tapping the backdrop closes it with role "backdrop", unless BackdropDismiss is false; under the same condition the system back button closes it with role "back".

razor
<IonButton OnClick="Open">More</IonButton>

@* Event anchors the popover to the tapped element; without it the popover is centered. *@
<IonPopover @bind-IsOpen="_isOpen" Event="_event">
    <IonList>
        <IonItem Button="true" OnClick="@(() => _isOpen = false)">Rename</IonItem>
        <IonItem Button="true" OnClick="@(() => _isOpen = false)">Duplicate</IonItem>
        <IonItem Button="true" Lines="none" OnClick="@(() => _isOpen = false)">Move to trash</IonItem>
    </IonList>
</IonPopover>

@code {
    private bool _isOpen;
    private Miko.Events.MouseEventArgs? _event;

    private void Open(Miko.Events.MouseEventArgs e)
    {
        _event = e;
        _isOpen = true;
    }
}

Trigger does both at once: set it to the id of the button and the popover opens on its click, anchored to it, without an OnClick handler or an Event (see Opening from a trigger). With TriggerAction="context-menu" it opens on a long press instead — what a context menu is on a touch screen.

Position ​

With an Event, Side chooses which edge of the trigger the popover opens on: bottom (default), top, left, right, start (left), or end (right). It flips to the opposite side when that side has more room (for left / right, only when the content does not fit). Alignment lines it up with the trigger's start, center, or end; the default is start on md and center on ios. On the top and bottom sides, the popover is also kept 8 px inside the left and right screen edges. Arrow (default true) adds a .popover-arrow element, drawn only in ios mode as in Ionic. This port does not yet place or rotate it toward the trigger, so on ios Arrow="false" usually looks cleaner.

razor
<IonButton OnClick="Open">Info</IonButton>

@* Side picks the edge of the trigger (flipped when the viewport has no room on that side);
   Alignment lines the popover up with the trigger's start, center or end. *@
<IonPopover @bind-IsOpen="_isOpen"
            Event="_event"
            Side="top"
            Alignment="center"
            Arrow="false">
    <div class="ion-padding">Last synced 2 minutes ago.</div>
</IonPopover>

@code {
    private bool _isOpen;
    private Miko.Events.MouseEventArgs? _event;

    private void Open(Miko.Events.MouseEventArgs e)
    {
        _event = e;
        _isOpen = true;
    }
}

Using the controller ​

IonPopoverController.CreateAsync takes an IonPopoverOptions, where Content is a RenderFragment and Event anchors the popover. To return a choice, call DismissAsync(data) on the reference from the content, then read Data from OnDidDismissAsync().

razor
@inject IonPopoverController PopoverController

<IonButton OnClick="ShowAsync">Sort: @_sort</IonButton>

@code {
    private string _sort = "Newest";
    private IonOverlayReference? _popover;

    private async Task ShowAsync(Miko.Events.MouseEventArgs e)
    {
        _popover = await PopoverController.CreateAsync(new IonPopoverOptions
        {
            Event = e, // anchor to the tapped button
            Content = Options,
        });
        await _popover.PresentAsync();

        var result = await _popover.OnDidDismissAsync();
        if (result.Data is string sort)
            _sort = sort;
    }

    private Task PickAsync(string sort) => _popover?.DismissAsync(sort) ?? Task.CompletedTask;

    private RenderFragment Options =>
        @<IonList>
            <IonItem Button="true" OnClick="@(() => PickAsync("Newest"))">Newest</IonItem>
            <IonItem Button="true" OnClick="@(() => PickAsync("Oldest"))">Oldest</IonItem>
            <IonItem Button="true" Lines="none" OnClick="@(() => PickAsync("Title"))">Title</IonItem>
        </IonList>;
}

API ​

Every component also accepts Class (extra CSS classes), Style (an inline Style object) and Id (the root element's id) — see Conventions.

IonPopover ​

ParameterTypeDefaultDescription
Alignmentstring?nullHow the popover lines up with the Event target: "start" / "center" / "end" (Ionic alignment). Null uses the mode default ("start" on md, "center" on ios).
ArrowbooltrueIf true (default), a .popover-arrow element is rendered (Ionic arrow). This port does not position or rotate it toward the trigger.
BackdropDismissbooltrueIf true (default), tapping the backdrop dismisses the popover.
EventMouseEventArgs?nullThe click/pointer event used to anchor the popover. Controllers pass Ionic's event option here; declarative callers can bind the event received by their trigger.
IsOpenboolfalseWhether the popover is presented. Bind two-way with IsOpenChanged. Two-way bindable: @bind-IsOpen.
OverlayIdstring?nullOptional stable identifier used by the root overlay registry.
ShowBackdropbooltrueIf true (default), the backdrop is rendered. When false the backdrop element is omitted.
Sidestring"bottom"Which side of the Event target the popover opens on: "top" / "right" / "bottom" (default) / "left" / "start" (left) / "end" (right). It flips to the opposite side when that side has more room. The side used is stamped as popover-side-{side}. Without an Event the popover is centered.
Triggerstring?nullId of the element that opens the popover (Ionic trigger), e.g. <IonButton Id="open-popover">. Opening sets IsOpen, raises IsOpenChanged and anchors the popover to the pressed element (unless Event is set). The page must be inside an IonApp.
TriggerActionstring"click"How the Trigger element opens the popover (Ionic triggerAction): "click" (default) or "context-menu", which opens on a long press — what a context menu is on a touch screen. Other values behave like "click".
EventTypeDescription
IsOpenChangedEventCallback<bool>Raised with the new open state when the popover opens/closes.
OnDidDismissEventCallback<IonOverlayDismissEventArgs>Raised after the popover dismisses (Ionic ionPopoverDidDismiss), with the role ("backdrop" on a backdrop tap, otherwise the caller's role).
OnWillDismissEventCallback<IonOverlayDismissEventArgs>Raised before the popover dismisses (Ionic ionPopoverWillDismiss).
SlotTypeDescription
ChildContentRenderFragment?Content placed between the component's tags.

Types ​

IonPopoverOptions ​

Options for IonPopoverController.CreateAsync. Each property maps to the IonPopover parameter of the same name.

PropertyTypeDefaultDescription
ContentRenderFragment?nullThe popover content.
EventMouseEventArgs?nullPointer event used to anchor the popover to its presenting trigger.
BackdropDismissbooltrueIf true (default), tapping the backdrop dismisses the popover.
ShowBackdropbooltrueIf true (default), the backdrop is rendered.
Sidestring"bottom"Side of the trigger to open on (see IonPopover.Side).
Alignmentstring?nullAlignment with the trigger (see IonPopover.Alignment).
ArrowbooltrueIf true (default), renders the arrow element.
CssClassstring?nullExtra CSS class(es) for the popover host (its Class).

IonPopoverController ​

Creates popovers from code (Ionic's popoverController). Inject it; AddIonic() registers it.

MethodReturnsDescription
CreateAsync(IonPopoverOptions options)Task<IonOverlayReference>Creates a popover from options. Call IonOverlayReference.PresentAsync on the result to show it.

Styling ​

IonPopover has no theme token of its own. The content box uses the theme's BackgroundColor and TextColor, and the backdrop color comes from IonicTheme.Alert.BackdropColor (see Alert). The backdrop is much lighter on ios (opacity 0.08) than on md (0.32).

CSS classes ​

App stylesheet rules always win over Ionic's own rules (see Theming), so these classes can be targeted directly from GlobalStyles.cs.

SelectorElement
.ion-popoverThe full-screen host. Also carries the mode (md / ios); .overlay-hidden while closed.
.popover-side-{side}The side actually used after flipping: top, bottom, left, or right.
.popover-backdropThe dim layer (also .ion-backdrop); omitted when ShowBackdrop="false".
.popover-wrapperThe positioned box that holds the arrow and the content.
.popover-contentThe visible panel holding your content: width, background, radius, shadow.
.popover-arrowThe arrow element (Arrow="true").
csharp
// GlobalStyles.cs — a wider menu: <IonPopover Class="wide" …>
[".ion-popover.wide .popover-content"] = new()
{
    Width = Length.Px(320),
},

When an Event is set, the position calculation assumes the default content width (250 / 200 px), so a much wider panel near the right edge can overflow the screen.

Released under the MIT License.