Skip to content

Commit d60bb89

Browse files
committed
Add pagination docs
1 parent 461613a commit d60bb89

8 files changed

+359
-14
lines changed
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
<script setup lang="ts">
2-
import { ref } from 'vue'
3-
4-
const pageNumber = ref(2)
5-
</script>
6-
71
<template>
8-
<gv-pagination v-model="pageNumber" :total-pages="3"/>
2+
<gv-pagination :total-pages="3"/>
93
</template>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
4+
const currentPage = ref(1)
5+
</script>
6+
7+
<template>
8+
<gv-inset-text aria-live="polite">
9+
You are on page {{ currentPage }}
10+
</gv-inset-text>
11+
<gv-pagination v-model:currentPage="currentPage" :total-pages="3"/>
12+
</template>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<script setup lang="ts">
2+
import { computed } from 'vue'
3+
import type { Ref } from 'vue'
4+
const pages = [
5+
{ title: 'Content page A', content: 'This is content page A' },
6+
{ title: 'Content page B', content: 'This is content page B' },
7+
{ title: 'Content page C', content: 'This is content page C' },
8+
]
9+
10+
const currentPageIndex = ref(0)
11+
const contentElement: Ref<HTMLDivElement | null> = ref(null)
12+
13+
const currentPage = computed(() => {
14+
return pages[currentPageIndex.value]
15+
})
16+
17+
const previousPage = computed(() => {
18+
if(currentPageIndex.value > 0) {
19+
return pages[currentPageIndex.value-1]
20+
}
21+
return null
22+
})
23+
24+
const nextPage = computed(() => {
25+
if(currentPageIndex.value < pages.length-1) {
26+
return pages[currentPageIndex.value+1]
27+
}
28+
return null
29+
})
30+
31+
function handlePreviousClicked() {
32+
if(currentPageIndex.value > 0) {
33+
currentPageIndex.value--
34+
focusContent()
35+
}
36+
}
37+
38+
function handleNextClicked() {
39+
if(currentPageIndex.value < pages.length-1) {
40+
currentPageIndex.value++
41+
focusContent()
42+
}
43+
}
44+
45+
/* When the user changes page, we focus on the main content for accessibility.
46+
Screen reader users will hear the new page content being read, and the focus
47+
position will be in the right place for keyboard-only users to tab through the
48+
content.
49+
*/
50+
function focusContent() {
51+
if(contentElement.value) {
52+
contentElement.value.focus()
53+
}
54+
}
55+
</script>
56+
57+
<template>
58+
<div ref="contentElement" tabindex="-1">
59+
<h1 class="govuk-heading-l">
60+
{{ currentPage.title }}
61+
</h1>
62+
<p class="govuk-body">
63+
{{ currentPage.content }}
64+
</p>
65+
</div>
66+
<gv-pagination
67+
:previous-text="previousPage ? 'Previous' : ''"
68+
:previous-label="previousPage ? previousPage.title : null"
69+
:next-text="nextPage ? 'Next' : ''"
70+
:next-label="nextPage ? nextPage.title : null"
71+
@previousClicked="handlePreviousClicked"
72+
@nextClicked="handleNextClicked"
73+
/>
74+
</template>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<script setup lang="ts">
2+
import { computed, watch } from 'vue'
3+
import type { Ref } from 'vue'
4+
const pages = [
5+
{ title: 'Content page A', content: 'This is content page A' },
6+
{ title: 'Content page B', content: 'This is content page B' },
7+
{ title: 'Content page C', content: 'This is content page C' },
8+
]
9+
10+
// The current-page prop is 1-indexed - we will need to account for that when accessing the pages[] array
11+
const currentPageNumber = ref(1)
12+
const contentElement: Ref<HTMLDivElement | null> = ref(null)
13+
14+
const currentPage = computed(() => {
15+
return pages[currentPageNumber.value - 1]
16+
})
17+
18+
const previousPage = computed(() => {
19+
if(currentPageNumber.value > 1) {
20+
return pages[currentPageNumber.value-2]
21+
}
22+
return null
23+
})
24+
25+
const nextPage = computed(() => {
26+
if(currentPageNumber.value < pages.length) {
27+
return pages[currentPageNumber.value]
28+
}
29+
return null
30+
})
31+
32+
/* When the user changes page, we focus on the main content for accessibility.
33+
Screen reader users will hear the new page content being read, and the focus
34+
position will be in the right place for keyboard-only users to tab through the
35+
content.
36+
*/
37+
watch(currentPageNumber, () => {
38+
if(contentElement.value) {
39+
contentElement.value.focus()
40+
}
41+
})
42+
</script>
43+
44+
<template>
45+
<div ref="contentElement" tabindex="-1">
46+
<h1 class="govuk-heading-l">
47+
{{ currentPage.title }}
48+
</h1>
49+
<p class="govuk-body">
50+
{{ currentPage.content }}
51+
</p>
52+
</div>
53+
<gv-pagination
54+
variant="block"
55+
v-model:current-page="currentPageNumber"
56+
:total-pages="3"
57+
:previous-label="previousPage ? previousPage.title : null"
58+
:next-label="nextPage ? nextPage.title : null"
59+
/>
60+
</template>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<template>
2+
<gv-pagination
3+
:total-pages="3"
4+
page-href="#page-${pageNumber}"
5+
/>
6+
</template>

content/2.components/pagination.md

Lines changed: 201 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,213 @@ Help users navigate forwards and backwards through a series of pages - for examp
99
See the [GOV.UK Design System documentation on pagination](https://design-system.service.gov.uk/components/pagination/) for
1010
more information on when to use this component.
1111

12+
```vue
13+
<gv-pagination :total-pages="3"/>
14+
```
15+
16+
## Setting and monitoring the current page number
17+
18+
Your page will probably need to know the number of the current page so that it can render its content. You can bind a
19+
ref with `v-model:current-page` to set the current page when the pagination component is mounted and monitor when the user
20+
selects a different page.
21+
1222
```vue
1323
<script setup lang="ts">
1424
import { ref } from 'vue'
1525
16-
const pageNumber = ref(2)
26+
const currentPage = ref(1)
27+
</script>
28+
29+
<template>
30+
<gv-inset-text aria-live="polite">
31+
You are on page {{ currentPage }}
32+
</gv-inset-text>
33+
<gv-pagination v-model:currentPage="currentPage" :total-pages="3"/>
34+
</template>
35+
```
36+
37+
## For navigating between content pages
38+
39+
Use the ‘block’ style of pagination to let users navigate through related content that has been split across multiple pages.
40+
41+
You can use link labels to give context on what the neighbouring pages are about. Use the `previous-label` and `next-label` props.
42+
43+
You can use block-style pagination with or without passing `total-pages`.
44+
45+
### Without `total-pages`
46+
Block-style pagination will be used by default if you don't pass the `total-pages` prop. Listen to the `previousClicked`
47+
and `nextClicked` events to know when to change pages. Pass an empty string to `previous-text` and `next-text` to hide
48+
the Previous/Next links as appropriate.
49+
50+
```vue
51+
<script setup lang="ts">
52+
import { computed } from 'vue'
53+
import type { Ref } from 'vue'
54+
const pages = [
55+
{ title: 'Content page A', content: 'This is content page A' },
56+
{ title: 'Content page B', content: 'This is content page B' },
57+
{ title: 'Content page C', content: 'This is content page C' },
58+
]
59+
60+
const currentPageIndex = ref(0)
61+
const contentElement: Ref<HTMLDivElement | null> = ref(null)
62+
63+
const currentPage = computed(() => {
64+
return pages[currentPageIndex.value]
65+
})
66+
67+
const previousPage = computed(() => {
68+
if(currentPageIndex.value > 0) {
69+
return pages[currentPageIndex.value-1]
70+
}
71+
return null
72+
})
73+
74+
const nextPage = computed(() => {
75+
if(currentPageIndex.value < pages.length-1) {
76+
return pages[currentPageIndex.value+1]
77+
}
78+
return null
79+
})
80+
81+
function handlePreviousClicked() {
82+
if(currentPageIndex.value > 0) {
83+
currentPageIndex.value--
84+
focusContent()
85+
}
86+
}
87+
88+
function handleNextClicked() {
89+
if(currentPageIndex.value < pages.length-1) {
90+
currentPageIndex.value++
91+
focusContent()
92+
}
93+
}
94+
95+
/* When the user changes page, we focus on the main content for accessibility.
96+
Screen reader users will hear the new page content being read, and the focus
97+
position will be in the right place for keyboard-only users to tab through the
98+
content.
99+
*/
100+
function focusContent() {
101+
if(contentElement.value) {
102+
contentElement.value.focus()
103+
}
104+
}
17105
</script>
18106
19107
<template>
20-
<gv-pagination v-model="pageNumber" :total-pages="3"/>
108+
<div ref="contentElement" tabindex="-1">
109+
<h1 class="govuk-heading-l">
110+
{{ currentPage.title }}
111+
</h1>
112+
<p class="govuk-body">
113+
{{ currentPage.content }}
114+
</p>
115+
</div>
116+
<gv-pagination
117+
:previous-text="previousPage ? 'Previous' : ''"
118+
:previous-label="previousPage ? previousPage.title : null"
119+
:next-text="nextPage ? 'Next' : ''"
120+
:next-label="nextPage ? nextPage.title : null"
121+
@previousClicked="handlePreviousClicked"
122+
@nextClicked="handleNextClicked"
123+
/>
21124
</template>
22125
```
126+
127+
### With `total-pages`
128+
If you pass a value for `total-pages`, the pagination will show as a list of page numbers by default. You can override
129+
this by passing `variant="block"`.
130+
131+
```vue
132+
<script setup lang="ts">
133+
import { computed, watch } from 'vue'
134+
import type { Ref } from 'vue'
135+
const pages = [
136+
{ title: 'Content page A', content: 'This is content page A' },
137+
{ title: 'Content page B', content: 'This is content page B' },
138+
{ title: 'Content page C', content: 'This is content page C' },
139+
]
140+
141+
// The current-page prop is 1-indexed - we will need to account for that when accessing the pages[] array
142+
const currentPageNumber = ref(1)
143+
const contentElement: Ref<HTMLDivElement | null> = ref(null)
144+
145+
const currentPage = computed(() => {
146+
return pages[currentPageNumber.value - 1]
147+
})
148+
149+
const previousPage = computed(() => {
150+
if(currentPageNumber.value > 1) {
151+
return pages[currentPageNumber.value-2]
152+
}
153+
return null
154+
})
155+
156+
const nextPage = computed(() => {
157+
if(currentPageNumber.value < pages.length) {
158+
return pages[currentPageNumber.value]
159+
}
160+
return null
161+
})
162+
163+
/* When the user changes page, we focus on the main content for accessibility.
164+
Screen reader users will hear the new page content being read, and the focus
165+
position will be in the right place for keyboard-only users to tab through the
166+
content.
167+
*/
168+
watch(currentPageNumber, () => {
169+
if(contentElement.value) {
170+
contentElement.value.focus()
171+
}
172+
})
173+
</script>
174+
175+
<template>
176+
<div ref="contentElement" tabindex="-1">
177+
<h1 class="govuk-heading-l">
178+
{{ currentPage.title }}
179+
</h1>
180+
<p class="govuk-body">
181+
{{ currentPage.content }}
182+
</p>
183+
</div>
184+
<gv-pagination
185+
variant="block"
186+
v-model:current-page="currentPageNumber"
187+
:total-pages="3"
188+
:previous-label="previousPage ? previousPage.title : null"
189+
:next-label="nextPage ? nextPage.title : null"
190+
/>
191+
</template>
192+
```
193+
194+
## Adding URLs to the links
195+
196+
We strongly recommend that you pass a URL to `page-href` (and `previous-href`/`next-href` if using block style) so that the
197+
pagination links can function as normal links. This will allow users to:
198+
199+
* open pagination links in new tabs
200+
* use the browser back button
201+
* share links to specific pages
202+
203+
Include the `${pageNumber}` placeholder in the URL you pass. The placeholder will be replaced with the appropriate number
204+
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,
205+
the hash or as part of the path.
206+
207+
Before the component is rendered, you should parse the page number from the URL and pass it to the pagination component
208+
with `v-model:current-page` (not shown in this example).
209+
210+
```vue
211+
<gv-pagination
212+
:total-pages="3"
213+
page-href="#page-${pageNumber}"
214+
/>
215+
```
216+
217+
If you're using block mode without passing `total-pages` you can also pass `previous-href` and `next-href`.
218+
219+
You can [use router-link or nuxt-link](/get-started/using-router-link-or-nuxt-link) for your navigation links if needed using the `link-component` prop.
220+
221+
::gvd-options{component="Pagination"}

0 commit comments

Comments
 (0)