Pagination states where a reader is in a paged collection, offers the pages next to that place,
and keeps the two ends of the collection one press away. It is the one navigation component
that has to work twice, because a paged collection either has addresses, in which case a page is
a link, or it does not, in which case a page is a handler.

The trail is computed from the collection rather than written by hand: the first and last page
are always offered, a window of pages sits either side of the reader, and a gap between two
shown pages becomes an ellipsis that is decoration rather than a control.

```tsx demo="navigation/pagination-preview"
```

## Usage

```tsx
import { Pagination } from "@asheeui/web";

// `page` is the page the collection is showing, held by the page that owns it.
<Pagination page={page} pageCount={24} onPageChange={setPage} />
```

`page` is counted from one and is clamped to the collection, so a state that has drifted past
the last page renders the last page rather than an empty trail. An empty collection still
renders its controls, disabled, so a page does not have to guard the trail while its first
response is in flight.

## The window

`siblingCount` is how many pages are shown on each side of the reader, and it defaults to `1`:
one page back, the current page, one page forward. The window clamps at the ends of the
collection rather than sliding, so the first page of twenty reads `1 2 … 20` and the trail
narrows at the boundary instead of shifting.

`showEdges` adds a control for the first and last page, either side of the previous and next
ones. The pairs wear the same chevron, so only their names tell them apart.

```tsx demo="navigation/pagination-window"
```

## Links or buttons

`hrefForPage` decides the element and the meaning at once. Supply it and every control is an
anchor whose destination is what the function returns, which is what a collection with real
addresses wants: a page can be opened in a new tab, copied, shared and crawled. Leave it out and
every control is a button that reports the chosen page through `onPageChange`.

```tsx demo="navigation/pagination-links"
```

The current page is marked `aria-current="page"` in both modes, and is never reported as a
change, because it is already where the reader is. In link mode the report still happens: pressing
an anchor calls `onPageChange` as well as navigating, so a page can keep its own state in step with
the address. A control that cannot be used, the previous arrow on the first page, loses its
destination and its tab stop, rather than keeping an `href` to a page that does not exist.

`link={{ component, props }}` renders every anchor as the application's own router link, so a
paginated collection with real addresses can still navigate client-side. See
[Links and substitution](/concepts/substitution).

## Props

```props Pagination
```

The registered defaults are `size` `md`, `radius` `md`, `siblingCount` `1` and `showEdges`
`false`. `size` reaches the controls in both modes, so a trail of links is as large as a trail of
buttons. `variant` and `color` are deliberately not registered: they resolve from the
application's `defaultVariant` and `defaultColor`, falling back to `bordered` and `primary`, so a
product states its control treatment once rather than at every trail.

`page`, `pageCount`, `hrefForPage`, `link`, `onPageChange`, `label` and `isDisabled` are
instance-only, because where a collection is, how it is addressed and whether it is loading are
statements about one collection rather than about the design. `label` names the landmark and
defaults to `Pagination` in the component rather than in configuration.

## Accessibility

- The trail is a `nav` landmark named `Pagination` by default. `label` renames it, and a page
  with two trails should name both, so they can be told apart in a landmark list.
- The controls are an ordered list, so a reader is told how many there are, and every control
  has a name of its own: `Page 4`, `Previous page`, `Next page`, `First page`, `Last page`. The
  chevrons are decorative and hidden from the accessibility tree, and so is the ellipsis between
  two shown pages, because a gap read aloud is noise.
- The current page carries `aria-current="page"`, so the reader's place is announced rather than
  only coloured.
- At the ends of the collection the previous and next controls are `aria-disabled`: in button
  mode the press is refused and the control stays in the reading order, so a reader can still
  find out that there is nothing before the first page.

## Related

```related tabs, sidebar, dropmenu
```
