forty-cdk
llms.txt

Primitives

Pagination

A navigation landmark that derives a visible page list with ellipsis gaps from page, count, siblingCount and boundaryCount, with previous / next buttons and aria-current='page' on the active page.

forty-cdk/pagination WAI-ARIA APG

Walk the pages with the pointer or the keyboard. The current page is aria-current="page", and the ends reflect data-disabled on the arrow that has nowhere to go.

Anatomy

<nav forPagination [(page)]="page" [count]="20" ariaLabel="Pagination" #pg="forPagination">
  <button forPaginationPrevious ariaLabel="Previous page">
    <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
      <path
        d="m15.75 19.5-7.5-7.5 7.5-7.5"
        fill="none"
        stroke="currentColor"
        stroke-width="1.75"
        stroke-linecap="round"
        stroke-linejoin="round"
      />
    </svg>
  </button>

  <!-- one item per entry in pg.items() — a page button per 'page' entry -->
  <button forPaginationItem [page]="item.value!">{{ item.value }}</button>
  <!-- an aria-hidden gap per 'ellipsis' entry -->
  <span aria-hidden="true">…</span>

  <button forPaginationNext ariaLabel="Next page">
    <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
      <path
        d="m8.25 4.5 7.5 7.5-7.5 7.5"
        fill="none"
        stroke="currentColor"
        stroke-width="1.75"
        stroke-linecap="round"
        stroke-linejoin="round"
      />
    </svg>
  </button>
</nav>

Examples

Driving a data list

Pagination is headless state: derive count from your data, then slice the visible rows from page(). Changing the page re-slices the list; the page model is the single source of truth shared by the rows and the controls.

  • INV-1001Acme$120.00
  • INV-1002Globex$157.00
  • INV-1003Initech$194.00
  • INV-1004Umbrella$231.00
  • INV-1005Soylent$268.00

1–5 of 23 invoices

API

ForPagination

PropertyTypeDescription
page
model
Two-way bindable. The currently active page number.
Default: —
count
input
Total number of pages.
Default: —
siblingCount
input
Number of page buttons to show on each side of the current page.
Default: —
boundaryCount
input
Number of page buttons to always show at the start and end of the list.
Default: —
ariaLabel
input
Accessible label for the navigation landmark.
Default: —
Data attributeValues
data-disabledpresent (no value) when disabled is set

ForPaginationItem

PropertyTypeDescription
page
input
The page number this button represents.
Default: —

ForPaginationPrevious

PropertyTypeDescription
ariaLabel
input
Accessible label for the previous-page button.
Default: —

ForPaginationNext

PropertyTypeDescription
ariaLabel
input
Accessible label for the next-page button.
Default: —

Accessibility

Implements the WAI-ARIA navigation landmark pattern.

  • Navigation landmark. [forPagination] applies role="navigation". Set ariaLabel (e.g. "Pagination") so the landmark is distinguishable from other navigation regions on the page.
  • Current page. [forPaginationItem] reflects aria-current="page" on the active page button so screen-reader users know which page they are on.
  • Disabled prev/next. [forPaginationPrevious] and [forPaginationNext] use the native disabled attribute at the boundaries, which suppresses click and removes the element from the tab order.

Styling

forty-cdk ships no styles. Style the current page via [aria-current="page"] and disabled prev/next via :disabled.

[forPaginationItem][aria-current='page'] {
  font-weight: bold;
}

[forPaginationPrevious]:disabled,
[forPaginationNext]:disabled {
  opacity: 0.4;
  pointer-events: none;
}

Wrapping in a design system

Subclass the root and re-provide FOR_PAGINATION_CONTEXT with useExisting pointing at the subclass, since Angular does not inherit a directive's providers; Wrapping non-form roots walks the pattern.