Paginator

A paginator steps through data shown in pages and tells readers where they are in the set. It holds only the numbers and fires an event on each move, so your page decides which rows to show. The paginators below are live, so press the arrows and watch the position change.

Reference docs⁠

BlazorReactWebOverviewExamplesAPIAccessibility

Built in⁠

Using paginators well⁠

  • Put the paginator at the end of the table or list it pages, aligned to the trailing edge.
  • Set no-border when the paginator sits inside a table that already draws a border.
  • Set items-per-page for the page size you want, or give items-per-page-selection and let its first value apply.
  • Slice or fetch the rows in your own listener, and read page-number from the paginator when the page size changes.
  • Keep the default range text, in the form first-last of total, and replace it with positionFormatter only to translate it.

These rules follow Material 3 Expressive's guidance for data tables, on material.io.

Position and pages⁠

item-count is the total number of items, and items-per-page is how many one page shows. The paginator works out the page count from the two and shows the range, such as 21-30 of 100.

page-number starts at 0, so page-number="2" is the third page. The range text and the live region count from 1. Setting it beyond the last page moves it back to the last one, and fires no event.

items-per-page defaults to 12, so a paginator with only item-count set reads 1-12 of the total. Set it for any other page size.

Page size⁠

items-per-page-selection takes an array of numbers and adds a select for them. Set it from script, since an array is not a plain attribute. With one number the select is hidden, and with none there is no select. The first number sets the starting page size.

Changing the size keeps the reader near the same items and fires items-per-page-change. No page-number-change fires for the recomputed page, so read page-number from the paginator in that listener.

positionFormatter and itemsPerPageFormatter take functions that return the range text and each option's text, or a promise of it, so a formatter can fetch a translation. The default text shows until the promise resolves. The preview cannot pass a function, so set them from script. The button names and the "Page N of M" announcement stay English.

Moving by code⁠

firstPage, previousPage, nextPage, and lastPage do what the four buttons do. Each fires page-number-change with the new pageNumber when the page changes, and does nothing at an end or while the paginator is disabled.

Setting page-number moves the paginator without an event. Listen for the event to learn what the reader did, and set the property to move the paginator. The demo sets page-number from a variable, so its buttons move the paginator, and the arrows report their change in the line below.

Disabled⁠

disabled disables all four buttons and the page size select together. There is no softer state: the controls leave the Tab order while it is set. Use it while the page fetches the next rows.

In a bordered table⁠

The paginator draws a border along its top edge. Set no-border to remove it where the table supplies its own. The paginator is 48 pixels tall and aligns to the trailing edge of its container.

Properties⁠

PropertyAttributeTypeDescription
disableddisabledbooleandefault falseWhether the paginator controls are disabled. When disabled, the navigation buttons and select are non-interactive, and firstPage(), previousPage(), nextPage() and lastPage() do nothing. See Disabled.
itemCountitem-countnumberdefault 0Total number of items being paginated. Used to calculate the number of pages and position display. See Position and pages.
itemsPerPageitems-per-pagenumberdefault 12The number of items on a page. When items-per-page-selection is set and does not offer this number, the paginator takes that list's first value. See Position and pages.
itemsPerPageFormatter(itemsPerPage: number) => Promise<string>Custom formatter for the items-per-page display text. Receives the current items per page value, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (n) => n + " éléments par page"). See Page size.
itemsPerPageSelectionitems-per-page-selectionnumber[]default []Available options for items per page in the dropdown. Example: [10, 25, 50, 100]. The select dropdown is hidden if only one option. See Page size.
noBorderno-borderbooleandefault falseHides the top border. Set to true when used inside a data table that already has borders. See In a bordered table.
pageNumberpage-numbernumberdefault 0The current page, counted from 0. Set it to change page from code. Setting it fires no event, and a value out of range is clamped to the first or last page. See Position and pages, Page size, Moving by code.
positionFormatter(first: number, last: number, total: number) => Promise<string>Custom formatter for the position display text. Receives first item index, last item index, and total count, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (f, l, t) => f + "-" + l + " sur " + t). See Page size.

Events⁠

EventTypeDetailDescription
page-number-changePageNumberChangeEventPageNumberChangeEventDetailWhen the page changes through a button or a page method. It bubbles and is composed.
items-per-page-changeItemsPerPageChangeEventItemsPerPageChangeEventDetailWhen the user chooses a different items-per-page value. The page number is recomputed without a page-number-change event. It bubbles and is composed.

Methods⁠

MethodReturnsDescription
firstPage()voidGoes to the first page, firing page-number-change if the page changes. Does nothing while disabled is set.
lastPage()voidGoes to the last page, firing page-number-change if the page changes. Does nothing while disabled is set.
nextPage()voidGoes to the next page, firing page-number-change if the page changes. Does nothing while disabled is set.
previousPage()voidGoes to the previous page, firing page-number-change if the page changes. Does nothing while disabled is set.

Props⁠

PropTypeDescription
disabledbooleandefault falseWhether the paginator controls are disabled. When disabled, the navigation buttons and select are non-interactive, and firstPage(), previousPage(), nextPage() and lastPage() do nothing. See Disabled.
itemCountnumberdefault 0Total number of items being paginated. Used to calculate the number of pages and position display. See Position and pages.
itemsPerPagenumberdefault 12The number of items on a page. When itemsPerPageSelection is set and does not offer this number, the paginator takes that list's first value. See Position and pages.
itemsPerPageFormatter(itemsPerPage: number) => Promise<string>Custom formatter for the items-per-page display text. Receives the current items per page value, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (n) => n + " éléments par page"). See Page size.
itemsPerPageSelectionnumber[]default []Available options for items per page in the dropdown. Example: [10, 25, 50, 100]. The select dropdown is hidden if only one option. See Page size.
noBorderbooleandefault falseHides the top border. Set to true when used inside a data table that already has borders. See In a bordered table.
pageNumbernumberdefault 0The current page, counted from 0. Set it to change page from code. Setting it fires no event, and a value out of range is clamped to the first or last page. See Position and pages, Page size, Moving by code.
positionFormatter(first: number, last: number, total: number) => Promise<string>Custom formatter for the position display text. Receives first item index, last item index, and total count, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (f, l, t) => f + "-" + l + " sur " + t). See Page size.

Events⁠

PropArgumentDescription
onPageNumberChangePageNumberChangeEventWhen the page changes through a button or a page method. It bubbles and is composed. Its detail carries pageNumber.
onItemsPerPageChangeItemsPerPageChangeEventWhen the user chooses a different items-per-page value. The page number is recomputed without a page-number-change event. It bubbles and is composed. Its detail carries itemsPerPage.

Methods⁠

Call these on the element the ref holds.

MethodReturnsDescription
firstPage()voidGoes to the first page, firing page-number-change if the page changes. Does nothing while disabled is set.
lastPage()voidGoes to the last page, firing page-number-change if the page changes. Does nothing while disabled is set.
nextPage()voidGoes to the next page, firing page-number-change if the page changes. Does nothing while disabled is set.
previousPage()voidGoes to the previous page, firing page-number-change if the page changes. Does nothing while disabled is set.

Parameters⁠

ParameterTypeDescription
Disabledbool?default falseWhether the paginator controls are disabled. When disabled, the navigation buttons and select are non-interactive, and firstPage(), previousPage(), nextPage() and lastPage() do nothing. See Disabled.
ItemCountint?default 0Total number of items being paginated. Used to calculate the number of pages and position display. See Position and pages.
ItemsPerPageint?default 12The number of items on a page. When ItemsPerPageSelection is set and does not offer this number, the paginator takes that list's first value. See Position and pages.
ItemsPerPageFormatterFunc<int, Task<string>>?Custom formatter for the items-per-page display text. Receives the current items per page value, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (n) => n + " éléments par page"). See Page size.
ItemsPerPageSelectionIEnumerable<int>?default []Available options for items per page in the dropdown. Example: [10, 25, 50, 100]. The select dropdown is hidden if only one option. See Page size.
NoBorderbool?default falseHides the top border. Set to true when used inside a data table that already has borders. See In a bordered table.
PageNumberint?default 0The current page, counted from 0. Set it to change page from code. Setting it fires no event, and a value out of range is clamped to the first or last page. See Position and pages, Page size, Moving by code.
PositionFormatterFunc<int, int, int, Task<string>>?Custom formatter for the position display text. Receives first item index, last item index, and total count, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (f, l, t) => f + "-" + l + " sur " + t). See Page size.

Event callbacks⁠

ParameterTypeDescription
OnPageNumberChangeEventCallback<PageNumberChangeEventArgs>When the page changes through a button or a page method. It bubbles and is composed. Its detail carries PageNumber.
OnItemsPerPageChangeEventCallback<ItemsPerPageChangeEventArgs>When the user chooses a different items-per-page value. The page number is recomputed without a page-number-change event. It bubbles and is composed. Its detail carries ItemsPerPage.

Inputs⁠

InputTypeDescription
disabledbooleandefault falseWhether the paginator controls are disabled. When disabled, the navigation buttons and select are non-interactive, and firstPage(), previousPage(), nextPage() and lastPage() do nothing. See Disabled.
itemCountnumberdefault 0Total number of items being paginated. Used to calculate the number of pages and position display. See Position and pages.
itemsPerPagenumberdefault 12The number of items on a page. When itemsPerPageSelection is set and does not offer this number, the paginator takes that list's first value. See Position and pages.
itemsPerPageFormatter(itemsPerPage: number) => Promise<string>Custom formatter for the items-per-page display text. Receives the current items per page value, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (n) => n + " éléments par page"). See Page size.
itemsPerPageSelectionnumber[]default []Available options for items per page in the dropdown. Example: [10, 25, 50, 100]. The select dropdown is hidden if only one option. See Page size.
noBorderbooleandefault falseHides the top border. Set to true when used inside a data table that already has borders. See In a bordered table.
pageNumbernumberdefault 0The current page, counted from 0. Set it to change page from code. Setting it fires no event, and a value out of range is clamped to the first or last page. See Position and pages, Page size, Moving by code.
positionFormatter(first: number, last: number, total: number) => Promise<string>Custom formatter for the position display text. Receives first item index, last item index, and total count, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (f, l, t) => f + "-" + l + " sur " + t). See Page size.

Outputs⁠

OutputEventDescription
cwPageNumberChangePageNumberChangeEventWhen the page changes through a button or a page method. It bubbles and is composed. Its detail carries pageNumber.
cwItemsPerPageChangeItemsPerPageChangeEventWhen the user chooses a different items-per-page value. The page number is recomputed without a page-number-change event. It bubbles and is composed. Its detail carries itemsPerPage.

Props⁠

PropTypeDescription
disabledbooleandefault falseWhether the paginator controls are disabled. When disabled, the navigation buttons and select are non-interactive, and firstPage(), previousPage(), nextPage() and lastPage() do nothing. See Disabled.
itemCountnumberdefault 0Total number of items being paginated. Used to calculate the number of pages and position display. See Position and pages.
itemsPerPagenumberdefault 12The number of items on a page. When itemsPerPageSelection is set and does not offer this number, the paginator takes that list's first value. See Position and pages.
itemsPerPageFormatter(itemsPerPage: number) => Promise<string>Custom formatter for the items-per-page display text. Receives the current items per page value, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (n) => n + " éléments par page"). See Page size.
itemsPerPageSelectionnumber[]default []Available options for items per page in the dropdown. Example: [10, 25, 50, 100]. The select dropdown is hidden if only one option. See Page size.
noBorderbooleandefault falseHides the top border. Set to true when used inside a data table that already has borders. See In a bordered table.
pageNumbernumberdefault 0The current page, counted from 0. Set it to change page from code. Setting it fires no event, and a value out of range is clamped to the first or last page. See Position and pages, Page size, Moving by code.
positionFormatter(first: number, last: number, total: number) => Promise<string>Custom formatter for the position display text. Receives first item index, last item index, and total count, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (f, l, t) => f + "-" + l + " sur " + t). See Page size.

Events⁠

EventTypeDescription
pageNumberChangePageNumberChangeEventWhen the page changes through a button or a page method. It bubbles and is composed. Its detail carries pageNumber.
itemsPerPageChangeItemsPerPageChangeEventWhen the user chooses a different items-per-page value. The page number is recomputed without a page-number-change event. It bubbles and is composed. Its detail carries itemsPerPage.

Props⁠

PropTypeDescription
disabledbooleandefault falseWhether the paginator controls are disabled. When disabled, the navigation buttons and select are non-interactive, and firstPage(), previousPage(), nextPage() and lastPage() do nothing. See Disabled.
itemCountnumberdefault 0Total number of items being paginated. Used to calculate the number of pages and position display. See Position and pages.
itemsPerPagenumberdefault 12The number of items on a page. When itemsPerPageSelection is set and does not offer this number, the paginator takes that list's first value. See Position and pages.
itemsPerPageFormatter(itemsPerPage: number) => Promise<string>Custom formatter for the items-per-page display text. Receives the current items per page value, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (n) => n + " éléments par page"). See Page size.
itemsPerPageSelectionnumber[]default []Available options for items per page in the dropdown. Example: [10, 25, 50, 100]. The select dropdown is hidden if only one option. See Page size.
noBorderbooleandefault falseHides the top border. Set to true when used inside a data table that already has borders. See In a bordered table.
pageNumbernumberdefault 0The current page, counted from 0. Set it to change page from code. Setting it fires no event, and a value out of range is clamped to the first or last page. See Position and pages, Page size, Moving by code.
positionFormatter(first: number, last: number, total: number) => Promise<string>Custom formatter for the position display text. Receives first item index, last item index, and total count, returns a promise of the display string. The text shows its default (or the last formatted text) until the promise resolves; a result for a replaced formatter is ignored. Useful for localization (e.g., async (f, l, t) => f + "-" + l + " sur " + t). See Page size.

Events⁠

PropTypeDescription
onPageNumberChangePageNumberChangeEventWhen the page changes through a button or a page method. It bubbles and is composed. Its detail carries pageNumber.
onItemsPerPageChangeItemsPerPageChangeEventWhen the user chooses a different items-per-page value. The page number is recomputed without a page-number-change event. It bubbles and is composed. Its detail carries itemsPerPage.

Names and states⁠

A screen reader announces the paginator as a navigation landmark holding a group of controls. It follows no single WAI-ARIA Authoring Practices pattern: its buttons follow the WAI-ARIA Authoring Practices: Button pattern, and its page size field is an ordinary select.

  • The landmark takes its name from an aria-label on the paginator, and is "Pagination navigation" when none is set. Give each paginator its own aria-label when two share a page, such as a table with controls above and below.
  • Only aria-label takes effect on the paginator. Any other aria-* attribute has no effect.
  • The controls sit in a group named "Pagination controls". The four buttons are named "First page", "Previous page", "Next page", and "Last page", and the select is named "Items per page". These names are fixed English text with no setting.
  • A screen reader announces "Page N of M" each time the page changes. positionFormatter and itemsPerPageFormatter do not reach it, so a translated page still has English there.
  • disabled takes every control out of the Tab order. The first and previous buttons disable on the first page, and the next and last buttons on the last.

Keyboard and focus⁠

Key Action
Tab Moves focus through the enabled buttons and the select, and on to the next control
Enter Activates the focused button
Space Activates the focused button

Tab, Enter, and Space work as they do on any button. The paginator adds no arrow, Home or End keys, so each button is its own Tab stop; the select's keys are the select's own.

  • A focus ring shows on keyboard focus.
  • A disabled button leaves the Tab order, so focus skips first and previous on the first page, and next and last on the last.

Pointer and touch⁠

  • The page buttons are icon buttons, and the paginator sets no touch target of its own, so their size follows the icon button's touch target setting. The row itself is 48 pixels tall.

Display settings⁠

  • Forced colors: the buttons and select follow the system colors.
  • Reduced motion: the paginator adds no motion of its own.
  • In a right-to-left layout the four icons mirror and the row's order reverses.

Standards⁠

With its defaults, the paginator meets four WCAG 2.2 success criteria:

  • 1.3.1 Info and Relationships (A)
  • 2.1.1 Keyboard (A)
  • 2.4.7 Focus Visible (AA)
  • 4.1.2 Name, Role, Value (A)

Two more depend on how you use it:

  • 2.4.6 Headings and Labels (AA): give each paginator its own aria-label when more than one appears on a page.
  • 2.5.8 Target Size (Minimum) (AA): keep the touch target of the page buttons at least 24 by 24 pixels.