Pagination
Page navigation with numbers, steps, a summary and a rows-per-page picker.
Pagination is a standalone component built from the kit's Button, IconButton and Select, plus a static ellipsis.
import { KuiPagination } from '@kikita-labs/ui';Bind currentPage with a signal. The current page carries aria-current and its own name, so the state is never colour alone.
<div class="pagination-example">
<kui-pagination ariaLabel="Project pages" [totalPages]="10" [(currentPage)]="page" />
<span>Current page: {{ page() }}</span>
</div>currentPage and pageSize are plain two-way bindings, not form values: pagination is page-level navigation state and is never placed inside kui-field.
compact (default) shows First, Prev, numbers and Next, Last. simple shows Prev, Page X of Y and Next for narrow layouts. full adds the Showing X to Y of Z summary and the rows-per-page picker. disabled blocks every control.
<div class="pagination-example">
<kui-pagination
ariaLabel="Simple pages"
variant="simple"
[totalPages]="12"
[(currentPage)]="page"
/>
<kui-pagination
ariaLabel="Full pages"
variant="full"
[totalPages]="12"
[totalItems]="289"
[(currentPage)]="page"
[(pageSize)]="pageSize"
/>
<kui-pagination
ariaLabel="Disabled pages"
size="sm"
[totalPages]="12"
[(currentPage)]="page"
disabled
/>
</div>siblingCount is how many numbers show beside the current page before an ellipsis, and boundaryCount how many always show at each edge. The ellipsis is a static aria-hidden span, never a button.
<div class="pagination-example">
<kui-pagination
ariaLabel="Wide window pages"
[totalPages]="42"
[siblingCount]="2"
[boundaryCount]="1"
[(currentPage)]="page"
/>
<kui-pagination
ariaLabel="Edge window pages"
[totalPages]="42"
[siblingCount]="0"
[boundaryCount]="2"
[(currentPage)]="page"
/>
</div>Pagination is a sibling of table[kuiTable], not nested in it: a table only allows table parts as children and holds the full dataset without a slicing concept. Page state is owned by the consuming component, as with mat-paginator and mat-table.
| Id | Name |
|---|---|
| 1 | Project 1 |
| 2 | Project 2 |
| 3 | Project 3 |
| 4 | Project 4 |
| 5 | Project 5 |
| 6 | Project 6 |
| 7 | Project 7 |
| 8 | Project 8 |
| 9 | Project 9 |
| 10 | Project 10 |
<div class="pagination-example">
<table kuiTable [data]="pageRows()">
<thead>
<tr>
<th kuiTh>Id</th>
<th kuiTh>Name</th>
</tr>
</thead>
<tbody>
@for (row of pageRows(); track row.id) {
<tr kuiRow [value]="row">
<td kuiCell>{{ row.id }}</td>
<td kuiCell>{{ row.name }}</td>
</tr>
}
</tbody>
</table>
<kui-pagination
ariaLabel="Table pages"
variant="full"
[totalPages]="totalPages()"
[totalItems]="allRows.length"
[pageSizeOptions]="[10, 20, 30]"
[(currentPage)]="page"
[(pageSize)]="pageSize"
/>
</div> Changing the rows-per-page picker sets pageSize and resets currentPage to 1 in the same update, since a stale page offset into a resized list would be wrong.
Set defaults.pagination once for the application or for a subtree. Each option resolves as local input > defaults.pagination.<option> > built-in default.
import { provideKikitaUi } from '@kikita-labs/ui';
export const appConfig: ApplicationConfig = {
providers: [
provideKikitaUi({
defaults: {
pagination: {
/* options below */
},
},
}),
],
};| Name | Type | Default | Description |
|---|---|---|---|
| variant | 'full' | 'compact' | 'simple' | — | Layout variant. |
| siblingCount | number | — | Pages shown on each side of the current page. |
| boundaryCount | number | — | Pages always shown at each edge. |
| pageSizeOptions | readonly number[] | — | Choices offered by the rows-per-page picker of the full variant. |
| firstIcon | KuiIconGlyph | — | Icon of the first-page button. Takes precedence over defaults.icons.first. See Structural Icons. |
| previousIcon | KuiIconGlyph | — | Icon of the previous control. Takes precedence over defaults.icons.previous. See Structural Icons. |
| nextIcon | KuiIconGlyph | — | Icon of the next control. Takes precedence over defaults.icons.next. See Structural Icons. |
| lastIcon | KuiIconGlyph | — | Icon of the last-page button. Takes precedence over defaults.icons.last. See Structural Icons. |
Set any of these on the component or an ancestor to restyle one part. Each token is optional: when it is not set, the part uses the role or scale token in the default column.
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-pagination-simple-label-color | CSS custom property | --kui-color-text | Simple label color |
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-pagination-summary-font-size | CSS custom property | --kui-text-xs-size | Summary font size |
| --kui-pagination-ellipsis-font-size | CSS custom property | --kui-text-sm-size | Ellipsis font size |
| --kui-pagination-simple-label-font-size | CSS custom property | --kui-text-sm-size | Simple label font size |
| --kui-pagination-simple-label-padding-inline | CSS custom property | --kui-space-2 | Simple label padding, inline |
| --kui-pagination-page-size-gap | CSS custom property | --kui-space-2 | Page size gap |
| --kui-pagination-page-size-label-font-size | CSS custom property | --kui-text-xs-size | Page size label font size |
Every text the component owns (accessible names, visible words, announcements) is a typed message with an English default. Override it for the application with provideKikitaUi({ messages }), or for a subtree with provideKuiMessages.
| Name | Type | Default | Description |
|---|---|---|---|
| label | string | — | Accessible name of the navigation landmark. Default Pagination. |
| first | string | — | First page button. Default First page. |
| previous | string | — | Previous page button. Default Previous page. |
| next | string | — | Next page button. Default Next page. |
| last | string | — | Last page button. Default Last page. |
| page | KuiMessageFn<{ page: number; current: boolean; }> | — | Accessible name of one page button. Default Page {page} or Page {page}, current. |
| rowsPerPage | string | — | Label of the rows per page picker. Default Rows per page. |
| summary | KuiMessageFn<{ start: number; end: number; total: number; }> | — | Summary text. Default Showing {start}–{end} of {total}. |
| simplePage | KuiMessageFn<{ page: number; total: number; }> | — | Label of the simple variant. Default Page {page} of {total}. |
Inputs verified against @kikita-labs/ui v2.0.0 public typings.
| Name | Type | Default | Description |
|---|---|---|---|
| variant | 'full' | 'compact' | 'simple' | undefined | undefined | Layout preset (defaults.pagination.variant, then compact). compact is First, Prev, numbers with ellipsis, Next and Last; simple is Prev, "Page X of Y" and Next; full adds the summary and the rows-per-page picker. |
| size | 'xs' | 'sm' | 'md' | 'lg' | undefined | undefined | Control size on the Button scale. Falls back to the root defaults.size, then md. |
| totalPages | number | - | Required total page count. Static numeric values are coerced; an invalid or non-positive value uses 1. |
| [(currentPage)] | number | 1 | Current page, 1-based. A plain two-way model, not a form value, so pagination is never placed in kui-field. An out-of-range binding is clamped. |
| siblingCount | number | undefined | undefined | Page numbers shown beside the current page before an ellipsis (defaults.pagination.siblingCount, then 1). |
| boundaryCount | number | undefined | undefined | Page numbers always shown at each edge (defaults.pagination.boundaryCount, then 1). |
| [(pageSize)] | number | 25 | Rows per page, used by the full variant. Changing the picker sets pageSize and resets currentPage to 1 in the same update. |
| pageSizeOptions | readonly number[] | undefined | undefined | Choices of the rows-per-page picker, full variant only (defaults.pagination.pageSizeOptions, then [10, 25, 50, 100]). |
| totalItems | number | undefined | totalPages * pageSize | Total item count for the "Showing X-Y of Z" summary, full variant only. |
| disabled | boolean | false | Disables every control with the native attribute, removing them from the tab order. |
| ariaLabel | string | undefined | undefined | Accessible name of the nav landmark. Falls back to the pagination.label message (Pagination). |
| messages | Partial<KuiPaginationMessages> | undefined | undefined | Per-instance text overrides: button names, rowsPerPage, summary and page. They win over scoped and root messages. |
| (currentPageChange) | number | - | Emitted whenever currentPage changes (model output). |
| (pageSizeChange) | number | - | Emitted whenever pageSize changes (model output). |
| --kui-pagination-gap / -summary-gap / -ellipsis-color | CSS custom properties | - | Gap between the controls, gap between the summary row and the controls, and the ellipsis and secondary text colour. |
| --kui-pagination-page-min-size-{xs,sm,md,lg} / -page-size-width | CSS custom properties | - | Square size of the page-number buttons per size and the fixed width (76px) of the rows-per-page picker. |
| KuiPaginationOptions | interface | - | Shape of defaults.pagination: variant, siblingCount, boundaryCount, pageSizeOptions and the four step icons. |
Pagination is a set of independent buttons in a navigation landmark.
- The controls sit in a
navlandmark named byariaLabelor thepagination.labelmessage, separate from the primary navigation. - The current page has
aria-current="page"and the namePage N, current. - First, Prev, Next and Last are icon buttons with a required
aria-label; at the range boundary they get the nativedisabledattribute and leave the tab order. - The ellipsis is
aria-hiddenand not focusable. - The full-variant summary is
aria-live="polite". - There is no roving tabindex or arrow-key navigation: Tab and Shift+Tab move between the non-disabled controls in visual order, and Enter or Space activates the focused one.
Documented limits of the installed package.
- There is no jump-to-page input; add a Number Input next to the group if a product needs it.
- The ellipsis is static and has no hover-to-jump affordance.
- The rows-per-page select sits in a label-less field with an
aria-labelon the input, so the open listbox panel carries no separate name. - A formal assistive-technology review has not been run.