Popover
A static page with IzzyBlazor's script. No circuit.
Usage
<Popover Label="Filters" StartIcon="Lucide.ListFilter" Title="Filter issues">
<Form Model="Filters" FormName="filters" OnValidSubmit="ApplyAsync">
<Checkbox @bind-Value="Filters!.Mine" />
<FormActions><Button Submit Size="ControlSize.Sm">Apply</Button></FormActions>
</Form>
</Popover>
{
[SupplyParameterFromForm(FormName = "filters")]
private IssueFilters? Filters { get; set; }
protected override void OnInitialized() => Filters ??= new();
}A popover is for content beside its trigger that people can leave without choosing: filters, a small form, an explanation. For a list of actions use a Menu, for a task that needs an answer a Dialog, and for a short label on hover a Tooltip.
A form in a popover
Use Title to head the panel and name it for screen readers; anything can go inside, such as a Form that filters the page.
Preview
Code
System.ComponentModel.DataAnnotations
<Row Gap="3" Wrap Align="Align.Center">
<Popover Label="Filters" StartIcon="Lucide.ListFilter" Title="Filter issues">
<Form Model="Model" FormName="issue-filters" OnValidSubmit="Apply" Gap="3">
<Checkbox @bind-Value="Model!.Open" />
<Checkbox @bind-Value="Model!.Closed" />
<Checkbox @bind-Value="Model!.Mine" />
<FormActions><Button Submit Size="ControlSize.Sm">Apply</Button></FormActions>
</Form>
</Popover>
<TextBlock As="span" Size="TextSize.Sm" Color="Color.Muted">_summary</TextBlock>
</Row>
{
[SupplyParameterFromForm(FormName = "issue-filters")]
private IssueFilters? Model { get; set; }
private string _summary = "Showing open issues";
protected override void OnInitialized() => Model ??= new();
private void Apply()
{
var states = (Model!.Open, Model.Closed) switch
{
(true, true) => "all issues",
(false, true) => "closed issues",
(true, false) => "open issues",
_ => "no issues",
};
_summary = $"Showing {states}" + (Model.Mine ? " assigned to you" : "");
}
public sealed class IssueFilters
{
[Display(Name = "Open issues")]
public bool Open { get; set; } = true;
[Display(Name = "Closed issues")]
public bool Closed { get; set; }
[Display(Name = "Assigned to me")]
public bool Mine { get; set; }
}
}Static: Opening it moves focus into the panel, and closing it from inside puts focus back on the button. Apply posts without a reload, and the panel stays open.
Placement and width
Use Placement for the side it opens on (BottomStart by default) and PanelWidth for a set width; otherwise it's as wide as its content, up to 24rem.
Preview
BottomStart, the default: under the trigger, lined up with its start.
Top: above the trigger, centered on it.
End with PanelWidth 14rem: after the trigger, the same width whatever it holds.
Code
@* Each opens where its Placement says, and moves to the other side when there's no room (beside it
with no room on either side, below it). Opening one closes another: Auto popovers close each
other. The Stack only gives the panels room in this frame. *@
<Stack Justify="Justify.Center" MinHeight="16.Rem" Grow>
<Row Gap="3" Wrap Justify="Justify.Center">
<Popover Label="Below" Title="Below, from the start" StartIcon="Lucide.PanelBottom">
<TextBlock Size="TextSize.Sm">BottomStart, the default: under the trigger, lined up with its start.</TextBlock>
</Popover>
<Popover Label="Above" Title="Above, centered" Placement="Placement.Top" StartIcon="Lucide.PanelTop">
<TextBlock Size="TextSize.Sm">Top: above the trigger, centered on it.</TextBlock>
</Popover>
<Popover Label="Beside" Title="Beside, a set width" Placement="Placement.End" PanelWidth="Length.Rem(14)"
StartIcon="Lucide.PanelRight">
<TextBlock Size="TextSize.Sm">End with PanelWidth 14rem: after the trigger, the same width whatever it holds.</TextBlock>
</Popover>
</Row>
</Stack>It moves to the other side when there's no room, and below the trigger when a panel beside it fits on neither side. Where the browser has no CSS anchor positioning the script places it; with JavaScript off there too, it opens in the middle of the screen.
Staying open
Use Mode="PopoverMode.Manual" for a panel that stays open while people work elsewhere on the page: Escape, a click outside and other popovers don't close it, so it shows a close button.
Preview
1. Bump the version in the project file.
2. Update the changelog.
3. Tag the commit and push the tag.
Code
@* The Stack only gives the panel room in this frame. *@
<Stack Justify="Justify.Center" MinHeight="13.Rem" Grow>
<Row>
<Popover Label="Release checklist" StartIcon="Lucide.Pin" Title="Before you release" Mode="PopoverMode.Manual" Placement="Placement.End">
<Stack Gap="2">
<TextBlock Size="TextSize.Sm">1. Bump the version in the project file.</TextBlock>
<TextBlock Size="TextSize.Sm">2. Update the changelog.</TextBlock>
<TextBlock Size="TextSize.Sm">3. Tag the commit and push the tag.</TextBlock>
</Stack>
</Popover>
</Row>
</Stack>ShowCloseButton adds the close button to an Auto popover too, or takes it off a manual one.
Your own trigger
Use Trigger for a button of your own, such as an info icon, and pass it context with @attributes, which connects it to the panel.
Preview
You're billed on the 1st of each month for the seats in use that day.
Read about billingCode
<Row Gap="1" Align="Align.Center">
<TextBlock As="span" Weight="FontWeight.Medium">Billing period</TextBlock>
<Popover Title="Billing period" Placement="Placement.Bottom" PanelWidth="Length.Rem(18)">
<Trigger>
<IconButton Icon="Lucide.Info" Label="About the billing period" Size="ControlSize.Sm"
Variant="ButtonVariant.Ghost" Accent="Accent.Neutral" @attributes="context" />
</Trigger>
<ChildContent>
<TextBlock Size="TextSize.Sm">You're billed on the 1st of each month for the seats in use that day.</TextBlock>
<Button Href="docs" Variant="ButtonVariant.Link" Size="ControlSize.Sm">Read about billing</Button>
</ChildContent>
</Popover>
</Row>The trigger must be a button with a name of its own. Without Trigger, the built-in button needs a Label, and StartIcon, Accent, Variant and Size style it.
Opening it from the server or C#
Use Open to show it when the page loads, and @bind-Open on an interactive page to open and close it from C# and follow what people do.
@* Interactive page: opens when C# sets _tipOpen, and follows the user. *@
<Popover Label="What's new" Title="What's new" @bind-Open="_tipOpen">
Saved filters are here: pick one from the list.
</Popover>
{
private bool _tipOpen = true;
}A popover opened this way leaves focus where it is. Open from the server needs the script: with JavaScript off the panel stays closed until its trigger is pressed.
Mode support
| Feature | Off | Static | Live |
|---|---|---|---|
| Opens and closes; Escape and a click outside close it | Yes | Yes | Yes |
| Focus moves in when opened and back when closed | Partly | Yes | Yes |
| Placed next to its trigger where CSS can't place it | No | Yes | Yes |
| Open from the server shows it | No | Yes | Yes |
| Open bound to C# | No | No | Yes |
Off: JavaScript disabled. Static: a static SSR page with IzzyBlazor's script. Live: an interactive page (Server, WebAssembly or Auto).
Accessibility
- The panel is a non-modal
dialognamed byTitle, or by its trigger without one; the trigger hasaria-haspopup="dialog". - With script, opening it moves focus to an element with
autofocus, or to the panel, and closing it puts focus back on the trigger. Focus isn't trapped: Tab can leave it. - In
Automode, Escape and a click outside close it. AManualpopover doesn't close on Escape, so it shows a close button, named "Close" (CloseLabel). - With JavaScript off, it opens and closes, and focus moves in only to an element with
autofocus. - A custom
Triggermust be abuttonwith a name of its own.
Parameters
| Prop | Type | Default |
|---|---|---|
LabelThe default trigger's text. | string? | |
CloseLabelThe close button's name. | string? | "Close" |
AccentThe default trigger's color. | Accent | Accent.Neutral |
VariantThe default trigger's weight. | ButtonVariant | ButtonVariant.Outline |
SizeThe default trigger's size. | ControlSize | ControlSize.Md |
StartIconAn icon before the default trigger's text. | IconData? | |
TriggerA custom trigger in place of the default button. | RenderFragment<IReadOnlyDictionary<string, object>>? | |
TitleA heading at the top, which also names the popover for screen readers. | string? | |
ShowCloseButtonShows a close button at the top. | bool? | |
ModeHow it closes. | PopoverMode | PopoverMode.Auto |
PlacementWhere it opens. | Placement | Placement.BottomStart |
PanelWidthThe width of the panel, such as Length.Rem(32) for a filter form. | Length? | computed |
ChildContentThe content. | RenderFragment? | |
@bind-OpenWhether it is open. | bool | false |
IdThe element id. | string? |
Plus 16 item props and 4 common props.
Full API