Skip to content
IzzyBlazor 0.1.0-alpha.18

Enter all results ↑ ↓ move Esc close

Pagination

Page links that keep the rest of the URL.

JavaScript off: what the HTML and CSS do on their own.

Usage

razor
@foreach (var order in Orders.Skip((Page - 1) * 20).Take(20))
{
    <OrderRow Order="order" />
}
<Pagination TotalItems="Orders.Count" PageSize="20" Label="Orders pages" />

@code {
    [SupplyParameterFromQuery(Name = "page")]
    private int? CurrentPage { get; set; }

    private int PageCount => Math.Max(1, (Orders.Count + 19) / 20);
    private int Page => Math.Clamp(CurrentPage ?? 1, 1, PageCount);
}

Each page is a link that sets ?page= and keeps the rest of the address, so paging works on static pages with JavaScript off, survives a reload and can be shared. Pagination only draws the links: the page reads the number and shows its own rows. A Table pages itself with the same links.

Pages in the address

Use TotalItems and PageSize, or PageCount, for how many pages there are, and read the page with [SupplyParameterFromQuery] to show its rows.

Preview

Showing orders 71–80 of 237

Code

Url.razor
<Stack Gap="3" Align="Align.Start" Grow>
    <TextBlock Size="TextSize.Sm" Color="Color.Muted">Showing orders @(First)–@(Last) of @Total</TextBlock>
    <Pagination TotalItems="Total" PageSize="PageSize" Label="Orders pages" />
</Stack>

@code {
    private const int Total = 237;
    private const int PageSize = 10;

    // The page's links set ?page=; read it here to show the right rows.
    [SupplyParameterFromQuery(Name = "page")]
    private int? CurrentPage { get; set; }

    private int Page => Math.Clamp(CurrentPage ?? 1, 1, (Total + PageSize - 1) / PageSize);
    private int First => (Page - 1) * PageSize + 1;
    private int Last => Math.Min(Page * PageSize, Total);
}

Page 1 leaves the key out of the address. Pagination treats a number past the last page as the last, so clamp your own the same way, as the example does; at the ends, previous or next stays in place, marked unavailable.

More than one on a page

Use QueryKey to give each pagination on a page its own key in the address, so they page apart, and Label to name each one for screen readers.

razor
<Pagination TotalItems="Orders.Count" QueryKey="orders-page" Label="Orders pages" />
<Pagination TotalItems="Returns.Count" QueryKey="returns-page" Label="Returns pages" />

A FilterForm drops a page key, or one ending in -page, when the filters change, so filtering starts again at page 1.

Sizes and how many pages show

Use Size to match the buttons and fields around it, Siblings for the pages on each side of the current one, and Boundaries for the pages always shown at each end.

Code

Sizes.razor
<Stack Gap="4" Align="Align.Start" Grow>
    <Pagination PageCount="24" Size="ControlSize.Sm" Siblings="0" QueryKey="small" Label="Small pagination" />
    <Pagination PageCount="24" QueryKey="medium" Label="Medium pagination" />
    <Pagination PageCount="24" Size="ControlSize.Lg" Boundaries="2" QueryKey="large" Label="Large pagination" />
</Stack>

The row keeps the same number of slots as the page moves, so the controls don't jump about. Below 640px only the current page's neighbors and the ends show, so it fits a phone.

Bound to C#

Use @bind-Page on an interactive page to page in C#: the pages become buttons that update the bound value, and the address stays as it is.

Preview

C# has page 6

Code

Bound.razor
<Stack Gap="3" Align="Align.Start" Grow>
    <Pagination @bind-Page="_page" PageCount="8" QueryKey="p" Label="Results pages" />
    <TextBlock Size="TextSize.Sm" Color="Color.Muted">C# has page <Code>@_page</Code></TextBlock>
</Stack>

@code {
    // Static pages have no C# to update, so the pages stay links that set ?p= (QueryKey): start from it.
    [SupplyParameterFromQuery(Name = "p")]
    private int? QueryPage { get; set; }

    private int _page;

    protected override void OnInitialized() => _page = QueryPage ?? 1;
}

Off: The pages are links that set ?page= and load the page again.

A static page has no C# to update, so there the pages stay links that set the key; start the bound value from the address, as the example does with ?p=, so both work.

Its own words

Use Label for the navigation landmark's name ("Pagination"), PreviousLabel and NextLabel for the arrows ("Previous page", "Next page"), and PageLabel for the word read before each number ("Page").

Mode support

What works in each mode, Pagination
FeatureOffStaticLive
Page links that set ?page= and keep the rest of the addressYesYesYes
Page bound to C#, with buttons in place of linksNoNoYes

Off: JavaScript disabled. Static: a static SSR page with IzzyBlazor's script. Live: an interactive page (Server, WebAssembly or Auto).

Accessibility

  • It renders a nav named "Pagination" (Label); give each one on a page its own Label.
  • Page numbers are read as "Page 3" (PageLabel), and the current page has aria-current="page".
  • Previous and next are named "Previous page" and "Next page" (PreviousLabel, NextLabel); at the ends they stay, with aria-disabled.
  • With @bind-Page they're buttons: the current page and a disabled previous or next stay buttons, so focus isn't lost when one is picked.
  • The gaps ("…") are hidden from screen readers.

Parameters

Pagination parameters
PropTypeDefault
@bind-PageThe current page, from 1.int?
PageCountHow many pages there are.int?
TotalItemsHow many items there are, with PageSize, in place of PageCount.int?
PageSizeItems per page, with TotalItems.int20
QueryKeyThe query-string key for the page.string"page"
SiblingsPages shown on each side of the current one.int1
BoundariesPages always shown at each end.int1
SizeButton size, shared with buttons and fields.ControlSizeControlSize.Md
LabelThe navigation landmark's name.string?"Pagination"
PreviousLabelThe previous button's name.string?"Previous page"
NextLabelThe next button's name.string?"Next page"
PageLabelRead before each page number by screen readers.string?"Page"

See also

  • Table: sort, filter, page and select, with state in the URL.
  • PrevNext: links to the pages before and after.
  • Breadcrumb: the path to the current page.