# Pagination

> Numbered pages, windowed around the current one, as real links.

`href` is a function from page number to URL, so pagination works for `/blog/2` and `/blog?page=2` alike. That makes every page a real link — crawlable, openable in a new tab, and working with no JavaScript, which is what a static site wants.

## Basic pagination

```javascript
pagination({ page: 1, count: 5, href: (page) => '#page-' + page })
```

## Windowing

The first and last pages are always shown, plus a window around the current one, with an ellipsis wherever the sequence jumps.

```javascript
stack({ gap: 'md' },
  pagination({ page: 1, count: 12, href: (page) => '#a-' + page }),
  pagination({ page: 6, count: 12, href: (page) => '#b-' + page }),
  pagination({ page: 12, count: 12, href: (page) => '#c-' + page }),
)
```

## Siblings

`siblings` is how many pages sit either side of the current one.

```javascript
stack({ gap: 'md' },
  pagination({ page: 6, count: 12, siblings: 0, href: (page) => '#d-' + page }),
  pagination({ page: 6, count: 12, siblings: 1, href: (page) => '#e-' + page }),
  pagination({ page: 6, count: 12, siblings: 3, href: (page) => '#f-' + page }),
)
```

## Ends

Previous is disabled on the first page and next on the last, so the control never offers a page that does not exist.

```javascript
stack({ gap: 'md' },
  pagination({ page: 1, count: 3, href: (page) => '#g-' + page }),
  pagination({ page: 3, count: 3, href: (page) => '#h-' + page }),
  pagination({ page: 1, count: 1, href: (page) => '#i-' + page }),
)
```

## Colors and labels

```javascript
stack({ gap: 'md' },
  pagination({ page: 3, count: 6, color: 'neutral', href: (page) => '#j-' + page }),
  pagination({
    page: 3,
    count: 6,
    color: 'success',
    previousLabel: 'Newer',
    nextLabel: 'Older',
    href: (page) => '#k-' + page,
  }),
)
```

## Without hrefs

With no `href`, the numbers render as buttons carrying `data-su-page` — for a page that filters in place with its own script. Prefer links when you can: they survive JavaScript being off.

```javascript
pagination({ page: 2, count: 4 })
```

## In a blog

The usual shape on a static site: `generateStaticParams` produces one page per slice, and `href` points at them.

```javascript
return (() => {
  const posts = 47
  const perPage = 10
  const current = 3

  return stack({ gap: 'md', align: 'center' },
    text({ variant: 'small', tone: 'muted' },
      'Showing ' + ((current - 1) * perPage + 1) + '–' + Math.min(current * perPage, posts) + ' of ' + posts,
    ),
    pagination({
      page: current,
      count: Math.ceil(posts / perPage),
      href: (page) => page === 1 ? '#blog' : '#blog-' + page,
    }),
  )
})()
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `page` | `number` | `1` | The current page. Clamped into range. |
| `count` | `number` | `1` | How many pages there are. |
| `href` | `(page: number) => string` | — | Page number to URL. Without it, pages render as buttons. |
| `siblings` | `number` | `1` | Pages shown either side of the current one. |
| `color` | `'primary' \| 'neutral' \| 'success' \| 'warning' \| 'danger'` | `'primary'` | Colour of the current page. |
| `label` | `string` | `'Pagination'` | Accessible name for the nav landmark. |
| `previousLabel` | `Child` | `'‹'` | Content of the previous control. |
| `nextLabel` | `Child` | `'›'` | Content of the next control. |
