Banner that stays dismissed
A maintenance notice above a small app: close it, move between pages and reload, and the server leaves it out for a year, until a new notice gets a new key. With JavaScript off it closes, but comes back on the next page.
NavigationManager Navigation
<Stack Gap="0" Grow>
@* Closed once, it stays closed for a year on every page, until the key changes. *@
<Banner @key="Key" Status="Status.Warning" Dismissible Remember="DismissMemory.Persistent" RememberKey="Key">
Scheduled maintenance on Sunday from 02:00 to 04:00 UTC. Exports pause during the window.
<BannerActions><Anchor Href="https://status.example.com" External>Status page</Anchor></BannerActions>
</Banner>
<Stack Gap="5" Padding="6">
<Row Gap="1" Wrap>
foreach (var tab in Pages)
{
<Button Href="Navigation.GetUriWithQueryParameter("page", tab.Id)" Size="ControlSize.Sm" Accent="Accent.Neutral"
Variant="(tab.Id == Current.Id ? ButtonVariant.Soft : ButtonVariant.Ghost)"
aria-current="(tab.Id == Current.Id ? "page" : null)">tab.Title</Button>
}
</Row>
<Stack Gap="2">
<Heading Level="2" Size="TextSize.Xl">Current.Title</Heading>
<TextBlock Color="Color.Muted">Current.Text</TextBlock>
</Stack>
<Divider />
<TextBlock Size="TextSize.Sm" Color="Color.Muted">
Notice <Code>Key</Code> ·
<Anchor Href="Navigation.GetUriWithQueryParameter("notice", Notice + 1)">Post a new notice</Anchor>
</TextBlock>
</Stack>
</Stack>
{
[SupplyParameterFromQuery(Name = "page")]
private string? PageId { get; set; }
[SupplyParameterFromQuery(Name = "notice")]
private int? NoticeQuery { get; set; }
private int Notice => NoticeQuery ?? 1;
// The cookie is ib-banner-{key}: a new key shows the banner to everyone again.
private string Key => $"maintenance-2026-11-v{Notice}";
private AppPage Current => Pages.FirstOrDefault(p => p.Id == PageId) ?? Pages[0];
}