# Pagination

> Page navigation for long lists. A CSS component with two classes and no JavaScript.

Navigation between pages of a long list. Each page is a link with its own address, not a button: the user can then open page three in a new tab, copy the address, and come back with the back button.

## How to use it

**Plain HTML**

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/pagination/pagination.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css -->
```

```html
<nav aria-label="Pagination">
<ul class="lt-pagination">
  <li><a href="#" aria-label="Previous page">Previous</a></li>
  <li><a href="#" aria-label="Page 1">1</a></li>
  <li><a href="#" aria-label="Page 2" aria-current="page">2</a></li>
  <li><a href="#" aria-label="Page 3">3</a></li>
  <li><span class="lt-pagination__gap">…</span></li>
  <li><a href="#" aria-label="Page 9">9</a></li>
  <li><a href="#" aria-label="Next page">Next</a></li>
</ul>
</nav>
```

**TypeScript**

```ts
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/pagination.css"
```

`lt` is used in two ways, and which one depends on whether you create the element or find it.

**If you create the markup,** spread the attributes in. That is the way in React, Astro and anything else that renders:

```tsx
import { lt } from "@lo-tek/interfaces/react"


<nav aria-label="Pagination">
  <ul {...lt.pagination()}>
    <li><a href="?page=1" aria-current="page">1</a></li>
    <li><a href="?page=2">2</a></li>
  </ul>
</nav>
```

The import is from `/react` here, since the block is JSX. From there the keys are `className` and `htmlFor`. In Astro and anything else without React, import `@lo-tek/interfaces` and you get `class` and `for`.

**If the element is already there,** set them on it. That is the way when you enhance HTML a server or a template has sent:

```ts
import { lt } from "@lo-tek/interfaces"


const list = document.querySelector<HTMLUListElement>("#pages")


lt.setAttributes(list, lt.pagination())
```

`lt.pagination.gap` gives the class for the gap in the number sequence. See [Type-safe use](/type-safe-use.md).

A number on its own says little when it is read out in the middle of a sequence. `aria-label="Page 3"` makes the link understandable, and `aria-current="page"` says which page the user is on.

If the user is on the first page, “Previous” should not be a link. Replace it with `<span aria-disabled="true">` or leave it out.

## Classes you can style

| Class | What it is |
| - | - |
| `.lt-pagination` | The list of pages. The links and buttons inside are styled by the component. |
| `.lt-pagination__gap` | The gap in the number sequence, as in “1 2 … 9 10” |

| Variable | Default |
| - | - |
| `--lt-pagination-gap` | `var(--lt-spacing-1)` |
| `--lt-pagination-size` | `var(--lt-spacing-10)` |
| `--lt-pagination-radius` | `var(--lt-spacing-1)` |

`--lt-pagination-size` is the minimum width and height of each number. WCAG 2.2 requires 24 pixels; the default here is 40, because a number in a long row is easy to miss with a finger.

See [Customising](/customising.md) for how the variables and the layer work.

## Accessibility

- Say where the user is, also outside the pagination itself: “Showing 21 to 40 of 184 cases” above the list helps more than the row of numbers alone.
- After a new page has loaded, move focus to the top of the list. Otherwise focus stays on a number that now means something else.
- If the list has few pages, show them all. The ”…” gap is only worth it from around ten pages up.
- If the content is an endless stream, a “Show more” button is often better than page numbers. Infinite scrolling without a button makes the footer unreachable.
