Pagination

Allows users to navigate to next or previous page when content is split into several pages

# Overview

# Pagination @ sm, md, lg

At the sm, md, and lg breakpoints, pagination displays as a list of number text links. Prev and Next links are also added when applicable.

The scoped slots can be used to override the default links rendered in the pagination. Useful for integrating with client-side routing, as a router-link can be rendered instead of a plain a tag. Pagination exposes 3 link scopedSlots: link, prevLink, and nextLink.

The 'link' slot scope exposes the following prop object:

attrs: {
  class,
  'aria-label',
  'aria-current',
  ref:,
},
href,
page,
content,
click,
1
2
3
4
5
6
7
8
9
10
  • class: a class to be applied to the link in order to match pagination styling
  • aria-label: default aria-label for this link
  • aria-current: reflects whether current link is the currently selected page
  • ref: vue ref for tracking the element. Required for internal component behavior
  • href: href that the link points to by default
  • page: the page number that corresponds to this link. NOTE: that you must manually update your v-model attribute to be the value of page whenever this link is clicked
  • content: the default content for that link
  • click: function ran when element is clicked. Required for internal component behavior

The prevLink and nextLink slot scopes expose the following prop object:

attrs: {
  class,
  'aria-label',
  ref,
},
href,
page,
content,
iconClass,
iconComponent,
iconPath,
click,
1
2
3
4
5
6
7
8
9
10
11
12
  • class: a class to be applied to the link in order to match pagination styling
  • aria-label: default aria-label for this link
  • ref: vue ref for tracking the element for internal component behavior
  • href: href that the link points to by default
  • page: the page number that corresponds to this link. NOTE: that you must manually update your v-model attribute to be the value of page whenever this link is clicked
  • content: the default content for that link
  • iconClass: a class to be applied to the prev/next arrow icon in order to match pagination styling
  • iconPath: the path to the icon in the Cedar Icon Library used for this link
  • iconComponent: name of the component used for this link
  • click: function ran when element is clicked. Required for internal component behavior

# Pagination @ xs

At the xs breakpoint, pagination adapts to a Select component using the native UI dropdown menu.

Image showing responsive pagination component using Select element

# Accessibility

This component complies with accessibility guidelines by doing the following:

  • Wraps the pagination links in a <nav> element to let screen readers recognize the pagination controls
  • Sets aria-label="pagination" to describe the type of navigation
  • Indicates the active page by adding aria-current="page" to the link that points to the current page
  • View these videos at a11ymattters, Accessible Pagination. They demonstrate before and after pagination tests using a screen reader voiceover

This component has compliance WCAG guidelines by:

  • WCAG 2.4.8: Information about the user's location within a set of Web pages is available
  • WCAG 3.2.3: Navigation patterns follow a consistent pattern. Only position pagination component at the bottom of the page
  • WCAG 2.4.3: Focus state receives focus in an order that preserves meaning
  • WCAG 2.4.7: Focus is visible
  • WCAG 2.5.5: Target size for pagination links are large enough for users to easily activate them

# Guidelines

# Use When

  • Providing navigation to break apart large quantities of content
  • Breaking up search result pages into manageable sections

# Don't Use When

  • Using lazy load or infinite scroll within an experience
  • Switching between slides or content in a carousel
  • Displaying editorial content. Instead, show entire article on one page

# Behavior

  • Page number links are truncated as follows: [first] ... [current-1] [current] [current+1] ... [last]
  • If there are 7 pages or fewer, all page number links will be shown
  • Prev or Next text links are removed when the first or last page are active

Within pagination, link styles are adapted

  • Text links are displayed as $text-color-primary-on-dark
  • Prev and Next links use the small size for the caret-left and caret-right icons

# Do / Don't

By default, pagination is center aligned under category or search results content.

Image showing center-aligned pagination
Do center align pagination beneath search results.
Image showing right-aligned pagination
Don't right or left align pagination.

The primary placement for pagination is at the bottom of a page that displays rows of content.

Image showing pagination at bottom of page below search results
Do place pagination at the bottom of search results.
Image showing pagination above search results
Don't place pagination above search results.

Use pagination logic to truncate link list, when possible.

Image showing pagination page number truncation
Do show the first, previous, next, and last page links when possible. If not, use the degraded designs.
Image showing pagination with all page numbers
Don't show all available pages.

# Responsiveness

Pagination adapts to a Select component with a native UI dropdown menu on XS breakpoints to provide a mobile-friendly experience.


# API

# Props

pages

name

array

type

N/A

default

Array of objects containing pagination data. Objects have structure of { page: number, url: string }. Required.

totalPages

name

number

type

null

default

Sets the total number of pages for displaying "Page x of <totalPages>". Sometimes the total number of pages is different than total page data objects in the pages array. For example, if only the next and previous pages are provided.

# Events

input

name

pageNumber, event

arguments

$emit event fired when page prop value is updated.

navigate

name

pageNumber, url, event

arguments

$emit event fired when page changes based on user interaction by clicking a link or selecting an option from the select on mobile.

# Scoped Slots

Find more information about using Slots in the article Getting Started as a Developer.

link

name

Scoped slot used to override the default page links used. Useful for integrating with client-side routing. See "Scoped Slots and vue-router" below for exposed prop API.

prevLink

name

Scoped slot used to override the default previous page link. Useful for integrating with client-side routing. See "Scoped Slots and vue-router" below for exposed prop API.

nextLink

name

Scoped slot used to override the default next page link. Useful for integrating with client-side routing. See "Scoped Slots and vue-router" below for exposed prop API.

# Usage

The CdrPagination component provides a current page number control and renders a list of links. The current page value should be bound using v-model in your app.

The CdrPagination component does not make data calls, render or track paginated data, or handle routing beyond simple anchor links. However, it does emit events if you need to customize routing or need to add additional application logic.

# Scoped Slots and vue-router

Previous, next, and individual page links can have their template overridden via scoped slots. While this isn't advisable under normal circumstances, it is necessary to make the component work with vue-router. It is similar to the scoped slot example but uses router-link with no click event (when paired with a computed prop v-model):

<cdr-pagination
  :pages="pages"
  :total-pages="20"
  v-model="page"
>
  <!-- Previous -->
  <template v-slot:prevLink="prevLink">
    <router-link
      v-bind="prevLink.attrs"
      :to="{ query: { 'page': prevLink.page } }"
      replace
    >
      <component
        :is="prevLink.iconComponent"
        :class="prevLink.iconClass"
      />
      {{ prevLink.content }}
    </router-link>
  </template>
  <!-- Single Page links -->
  <template v-slot:link="link">
    <router-link
      v-bind="link.attrs"
      :to="{ query: { 'page': link.page } }"
      replace
    >
      {{ link.page }}
    </router-link>
  </template>
  <!-- Next -->
  <template v-slot:nextLink="nextLink">
    <router-link
      v-bind="nextLink.attrs"
      :to="{ query: { 'page': nextLink.page } }"
      replace
    >
      {{ nextLink.content }}
      <component
        :is="nextLink.iconComponent"
        :class="nextLink.iconClass"
      />
    </router-link>
  </template>
</cdr-pagination>

...

<script>
...
computed: {
  page: {
    get() {
      return parseInt(this.$route.query['page'], 10) || 1;
    },
    set() {
      // No need to do anything for the component here
    },
  },
},
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# SEO

For best SEO support, use of pagination requires additional markup and logic in the <head> of the page.

See REI's SEO Confluence page on pagination for information on implementing this correctly on your page.

Note that REI has chosen HTML <link> elements instead of HTTP headers. Make sure to use fully qualified absolute URLs in the <link> elements instead of relative URLs.

For general recommendations, view Google's Search Console page, Indicating paginated content to Google.