Components

Pagination

Help users navigate forwards and backwards through a series of pages - for example, search results.

See the GOV.UK Design System documentation on pagination for more information on when to use this component.

<gv-pagination :total-pages="3"/>

Setting and monitoring the current page number

Your page will probably need to know the number of the current page so that it can render its content. You can bind a ref with v-model:current-page to set the current page when the pagination component is mounted and monitor when the user selects a different page.

You are on page 1
<script setup lang="ts">
import { ref } from 'vue'

const currentPage = ref(1)
</script>

<template>
  <gv-inset-text aria-live="polite">
    You are on page {{ currentPage }}
  </gv-inset-text>
  <gv-pagination v-model:currentPage="currentPage" :total-pages="3"/>
</template>

For navigating between content pages

Use the ‘block’ style of pagination to let users navigate through related content that has been split across multiple pages.

You can use link labels to give context on what the neighbouring pages are about. Use the previous-label and next-label props.

You can use block-style pagination with or without passing total-pages.

Without total-pages

Block-style pagination will be used by default if you don't pass the total-pages prop. Listen to the previousClicked and nextClicked events to know when to change pages. Pass an empty string to previous-text and next-text to hide the Previous/Next links as appropriate.

Content page A

This is content page A

<script setup lang="ts">
import { computed } from 'vue'
import type { Ref } from 'vue'
const pages = [
  { title: 'Content page A', content: 'This is content page A' },
  { title: 'Content page B', content: 'This is content page B' },
  { title: 'Content page C', content: 'This is content page C' },
]

const currentPageIndex = ref(0)
const contentElement: Ref<HTMLDivElement | null> = ref(null)

const currentPage = computed(() => {
  return pages[currentPageIndex.value]
})

const previousPage = computed(() => {
  if(currentPageIndex.value > 0) {
    return pages[currentPageIndex.value-1]
  }
  return null
})

const nextPage = computed(() => {
  if(currentPageIndex.value < pages.length-1) {
    return pages[currentPageIndex.value+1]
  }
  return null
})

function handlePreviousClicked() {
  if(currentPageIndex.value > 0) {
    currentPageIndex.value--
    focusContent()
  }
}

function handleNextClicked() {
  if(currentPageIndex.value < pages.length-1) {
    currentPageIndex.value++
    focusContent()
  }
}

/* When the user changes page, we focus on the main content for accessibility. 
   Screen reader users will hear the new page content being read, and the focus
   position will be in the right place for keyboard-only users to tab through the
   content.
 */
function focusContent() {
  if(contentElement.value) {
    contentElement.value.focus()
  }
}
</script>

<template>
  <div ref="contentElement" tabindex="-1">
    <h1 class="govuk-heading-l">
      {{ currentPage.title }}
    </h1>
    <p class="govuk-body">
      {{ currentPage.content }}
    </p>
  </div>
  <gv-pagination 
    :previous-text="previousPage ? 'Previous' : ''"
    :previous-label="previousPage ? previousPage.title : null"
    :next-text="nextPage ? 'Next' : ''"
    :next-label="nextPage ? nextPage.title : null" 
    @previousClicked="handlePreviousClicked"
    @nextClicked="handleNextClicked"
  />
</template>

With total-pages

If you pass a value for total-pages, the pagination will show as a list of page numbers by default. You can override this by passing variant="block".

Content page A

This is content page A

<script setup lang="ts">
import { computed, watch } from 'vue'
import type { Ref } from 'vue'
const pages = [
  { title: 'Content page A', content: 'This is content page A' },
  { title: 'Content page B', content: 'This is content page B' },
  { title: 'Content page C', content: 'This is content page C' },
]

// The current-page prop is 1-indexed - we will need to account for that when accessing the pages[] array
const currentPageNumber = ref(1)
const contentElement: Ref<HTMLDivElement | null> = ref(null)

const currentPage = computed(() => {
  return pages[currentPageNumber.value - 1]
})

const previousPage = computed(() => {
  if(currentPageNumber.value > 1) {
    return pages[currentPageNumber.value-2]
  }
  return null
})

const nextPage = computed(() => {
  if(currentPageNumber.value < pages.length) {
    return pages[currentPageNumber.value]
  }
  return null
})

/* When the user changes page, we focus on the main content for accessibility. 
   Screen reader users will hear the new page content being read, and the focus
   position will be in the right place for keyboard-only users to tab through the
   content.
 */
watch(currentPageNumber, () => {
  if(contentElement.value) {
    contentElement.value.focus()
  }
})
</script>

<template>
  <div ref="contentElement" tabindex="-1">
    <h1 class="govuk-heading-l">
      {{ currentPage.title }}
    </h1>
    <p class="govuk-body">
      {{ currentPage.content }}
    </p>
  </div>
  <gv-pagination
    variant="block"
    v-model:current-page="currentPageNumber"
    :total-pages="3"
    :previous-label="previousPage ? previousPage.title : null"
    :next-label="nextPage ? nextPage.title : null"
  />
</template>

We strongly recommend that you pass a URL to page-href (and previous-href/next-href if using block style) so that the pagination links can function as normal links. This will allow users to:

  • open pagination links in new tabs
  • use the browser back button
  • share links to specific pages

Include the ${pageNumber} placeholder in the URL you pass. The placeholder will be replaced with the appropriate number for each page, starting from 1. It's up to you how you use the page number in the URL - it could be in the query string, the hash or as part of the path.

Before the component is rendered, you should parse the page number from the URL and pass it to the pagination component with v-model:current-page (not shown in this example).

<gv-pagination
  :total-pages="3"
  page-href="#page-${pageNumber}"
/>

If you're using block mode without passing total-pages you can also pass previous-href and next-href.

You can use router-link or nuxt-link for your navigation links if needed using the link-component prop.

Props

NameTypeDescription
currentPage number
The number of the currently selected page. Use v-model:currentPage to keep track of the current page.

Defaults to 1.
variant string
Whether to show the pagination controls on top of each other as 'Previous' and 'Next' links (block) or as a list of numbers (list).

Allowed values: block, list.
totalPages number
The total number of pages in the pagination. Required if variant is list.
pageHref string
The URL the user should be taken to when they click a page number. The ${pageNumber} placeholder will be replaced with the number of the selected page.

Defaults to '#'.
landmarkLabel string
The label for the navigation landmark that wraps the pagination.

Defaults to 'results'.
previousText string
The link text to the previous page.

Defaults to 'Previous'.
previousLabel string
The optional label that goes underneath the link to the previous page, providing further context for the user about where the link goes.
previousHref string
The URL the user should be taken to when they click the 'Previous' link. The ${pageNumber} placeholder will be replaced with the number of the previous page. If you've provided totalPages and pageHref, this will default to pageHref with the number of the previous page replacing the ${pageNumber} placeholder.
nextText string
The link text to the previous page.

Defaults to 'Next'.
nextLabel string
The optional label that goes underneath the link to the next page, providing further context for the user about where the link goes.
nextHref string
The URL the user should be taken to when they click the 'Next' link. The ${pageNumber} placeholder will be replaced with the number of the next page. If you've provided totalPages and pageHref, this will default to pageHref with the number of the next page replacing the ${pageNumber} placeholder.
skipPagesThreshold number
If totalPages is above this threshold, the pagination control will show an ellipsis (...) to skip all pages except the first and last and a certain number of pages around the current page (see beforeAfterCount).
beforeAfterCount number
If the pagination control is skipping pages, this is the number of pages around the current page which will be shown. For example, if this is set to 2 and the current page is 15 out of 100, the pagination will show '1 ... 13 14 [15] 16 17 ... 100'

Defaults to 1.
linkComponent string|object
The component used to render previous, next and page links, for example RouterLink.

Defaults to 'a'.