Popover
JavaScript off: what the HTML and CSS do on their own.
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; }
}
}Off: It opens and closes with no script, but focus stays on the button until you Tab into the panel. Apply posts the form and the page loads again, with the panel closed.
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